<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.ocetechnology.com/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Wiki</id>
	<title>wiki - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.ocetechnology.com/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Wiki"/>
	<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php/Special:Contributions/Wiki"/>
	<updated>2026-10-22T11:16:50Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.36.1</generator>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=709</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=709"/>
		<updated>2021-10-01T12:40:14Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Two-phase build to miminise memory used */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=708</id>
		<title>OCEOS Operation</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=708"/>
		<updated>2021-10-01T12:35:38Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Changing the default trap handler */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Operations basics =&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library, header files(s), and application source files that can be compiled and linked with the standard BCC gcc or clang tools and libraries to provide a real-time multitasking application. OCEOS uses BCC library calls for some system functions. These functions are provided in the BCC board support package for the GR716. The minimum memory footprint for OCEOS is shown in the table below. Core modules occupy less than 10K bytes.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_size.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Operations manual =&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is structured as a set of managers each providing OCEOS service calls. &amp;lt;/br&amp;gt;&lt;br /&gt;
The activities supported by these managers are: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|''''' Initialization manager ''''':&lt;br /&gt;
|initializing the hardware and OCEOS itself&lt;br /&gt;
|-&lt;br /&gt;
|''''' Task manager ''''':&lt;br /&gt;
|handling tasks and jobs, including scheduling&lt;br /&gt;
|-&lt;br /&gt;
|''''' Interrupt manager ''''':&lt;br /&gt;
|setting up trap handlers&lt;br /&gt;
|-&lt;br /&gt;
|''''' Clock manager ''''':&lt;br /&gt;
|providing time of day, dates, and alarms&lt;br /&gt;
|-&lt;br /&gt;
|''''' Timer manager ''''':&lt;br /&gt;
|interval timing and alarms, timed outputs and jobs&lt;br /&gt;
|-&lt;br /&gt;
|''''' Mutex manager ''''':&lt;br /&gt;
|mutual exclusion management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Semaphore manager ''''':&lt;br /&gt;
|counting semaphore management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Data queue manager ''''':&lt;br /&gt;
|data queue management&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The directives provided by these managers are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== Set‐up and initialisation ==&lt;br /&gt;
&lt;br /&gt;
Setup for the use of OCEOS requires the user to prepare the development environment.&lt;br /&gt;
At a minimum this requires the installation for compilers, debug tool, editors, …etc.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
=== DMON OCEOS Support===&lt;br /&gt;
:OCE added OCEOS support to DMON to help user in debugging application software. Detailed manual and available functionality can be found [[DMON_OCEOS_Support|'''here''']].&lt;br /&gt;
&lt;br /&gt;
[[File:Cpu_load_main.png|600px|Cpu Load View]] [[File:Cpu_profile_main.png|600px|Cpu Profile View]]&lt;br /&gt;
&lt;br /&gt;
=== Files provided with OCEOS ===&lt;br /&gt;
&lt;br /&gt;
Unpack the OCEOS software into an appropriate folder on the computer. The folders are as follows:&lt;br /&gt;
&lt;br /&gt;
[[File:unzip_folders.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Documentation OCEOS User Manual and Quick Reference.&lt;br /&gt;
* include Include files required by the application&lt;br /&gt;
* OCEOS_GCC_LIB oceos.a object library for applications to be built with gcc&lt;br /&gt;
* OCEOS_LLNM_LIB oceos.a object library for applications to be built with llvm (32-bit)&lt;br /&gt;
* OCEOS_LLVM_REX_LIB oceos.a object library for applications to be built with llvm (16-bit REX mode)&lt;br /&gt;
* Sample Project c sources, include files, and make files for an example project&lt;br /&gt;
* UserManualTutorials c sources, include files, and make files for User Manual tutorials and application example &lt;br /&gt;
* Excel configuration file to help produce oceos_config.h can be downloaded from [[Media:OCEOS_Config.xlsx]] &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The source and build files associated with the example application referred to in this manual are located in the folder &amp;lt;installation-folder&amp;gt; \UserManualTutorials\asw.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''asw.h''' &amp;lt;blockquote&amp;gt;Simple application header.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''asw.c''' &amp;lt;blockquote&amp;gt;Simple application example. This file is a self-contained example of an OCEOS application including tasks, mutexes, semaphores, and dataqueues.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''oceos_config.h''' &amp;lt;blockquote&amp;gt;This is the OCEOS application header file where the developer specifies the number of tasks, mutexes, sempahores, dataqs, log entries, and readyq entries. These numbers are used to allocate the &lt;br /&gt;
memory required for storing oceos variables. The definitions to be specified follow.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_configuration2.jpg]]&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
Notes: &amp;lt;/br&amp;gt;&lt;br /&gt;
# The application must create the number of tasks, mutexes, semaphores or dataqs specified in this header, otherwise an error will be returned from oceos_init_finish().&lt;br /&gt;
# LOG_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# FIXED_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# DYN_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# Enumerated types are recommended for names of tasks, mutexes, semaphores and dataqs. This header file contains some examples.&lt;br /&gt;
&lt;br /&gt;
'''oceos_config.c''' &amp;lt;blockquote&amp;gt;This file contains the OCEOS data areas and the following functions:&lt;br /&gt;
# int application_init() This function initialises the oceos data area.&lt;br /&gt;
# void oceos_on_error(void* ptr) The developer should code this function to implement actions in case of a system error.&lt;br /&gt;
# void oceos_on_full_log(void* ptr)&lt;br /&gt;
The developer should code this function which is called when the system log is two-thirds full.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''makefile &amp;amp; makefile.mk''' &amp;lt;blockquote&amp;gt;These file are provided to facilitate building the asw application. Some local edits are required to point to the local compiler folders.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building the example application ===&lt;br /&gt;
&lt;br /&gt;
Download and install the BCC2 compiler [https://www.gaisler.com/index.php/downloads/compilers from here]. &lt;br /&gt;
&lt;br /&gt;
Use the Makefile provided or use the following commands to compile and link the application.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c asw.c -o asw.o&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c oceos_config.c -o oceos_config.o&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang asw.o oceos_config.o -o asw-gr716.elf -qbsp=gr716 -mcpu=leon3 -qsvt -qnano -Wall -LC:/projects/oce/oceos/trunk/oceos_product/oceoc/build/ -loceos -Wl,-Map=asw-gr716.map&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
# sparc-gaisler-elf-clang Ensure the path to the compiler has been configured. The llvm clang compiler is recommended as the OCEOS library was compiled with it.&lt;br /&gt;
# -I. -Iinclude -I&amp;lt;bcc-install-folder&amp;gt;/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include This -I option allows paths to include files to be passed to the compiler.&lt;br /&gt;
# -qbsp=gr716 This option specifies the compiler gr716 board support package.&lt;br /&gt;
# -mcpu=leon3 This option specifies the processor type.&lt;br /&gt;
# -Wall Display all warning messages.&lt;br /&gt;
# -c Compile only (linking not required).&lt;br /&gt;
# -o &amp;lt;filename&amp;gt; Specify the output filename.&lt;br /&gt;
# -qsvt Use the single-vector trap model described in “SPARC-V8 Supplement, SPARC-V8 Embedded (V8E) Architecture Specification”.&lt;br /&gt;
# -qnano Use a version of the newlib C library compiled for reduced foot print. The nano version implementations of the fprintf() fscanf() family of functions are not fully C standard compliant. Code size can decrease with up to # KiB when printf() is used.&lt;br /&gt;
# -L&amp;lt;path-to-oceos-library-file&amp;gt; Specify the path where liboceos.a is located.&lt;br /&gt;
# -loceos Instructs linker to use library liboceos.a&lt;br /&gt;
# -Wl,-Map=asw-gr716.map Instructs the linker to generate a map file with the name asw-gr716.map. This optional map file details the memory map of all functions and data.&lt;br /&gt;
# Consult the BCC manual for other options.&lt;br /&gt;
&lt;br /&gt;
The application executable (in this case asw.elf) can now be downloaded and executed on the target GR716 hardware. A debug tool such as DMON or GRMON is required for this. DMON provides specific support of OCEOS.&lt;br /&gt;
&lt;br /&gt;
'''''Important Note'''''&lt;br /&gt;
Up to BCC version 2.1.2 bcc_inline.h needs to be changed as it does not function on the GR716 as expected. The file is located in …\bcc-2.x.x-llvm\sparc-gaisler-elf\bsp\gr716\include\bcc\ for llvm and …\bcc-2.x.x-gcc\sparc-gaisler-elf\bsp\gr716\include\bcc for gcc.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* OCEOS comment out until BCC fix&lt;br /&gt;
 #ifdef __BCC_BSP_HAS_PWRPSR&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         uint32_t ret;&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
               &amp;quot;sll %4, %1, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;or %%o1, %2, %4\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;.word 0x83882000\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;rd %%psr, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;andn %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;wr %4, %%o2, %%psr\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;and %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;srl %%o2, %1, %0\n\t&amp;quot;&lt;br /&gt;
                 : &amp;quot;=r&amp;quot; (ret)&lt;br /&gt;
                 : &amp;quot;i&amp;quot; (PSR_PIL_BIT), &amp;quot;i&amp;quot; (PSR_ET), &amp;quot;i&amp;quot; (PSR_PIL), &amp;quot;r&amp;quot; &lt;br /&gt;
 (newpil)&lt;br /&gt;
                 : &amp;quot;o1&amp;quot;, &amp;quot;o2&amp;quot;&lt;br /&gt;
         );&lt;br /&gt;
         return ret;&lt;br /&gt;
 }&lt;br /&gt;
 #else &lt;br /&gt;
 */&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         register uint32_t _val __asm__(&amp;quot;o0&amp;quot;) = newpil;&lt;br /&gt;
         /* NOTE: nop for GRLIB-TN-0018 */&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
                 &amp;quot;ta %1\nnop\n&amp;quot; :&lt;br /&gt;
                 &amp;quot;=r&amp;quot; (_val) :&lt;br /&gt;
                 &amp;quot;i&amp;quot; (BCC_SW_TRAP_SET_PIL), &amp;quot;r&amp;quot; (_val)&lt;br /&gt;
         );&lt;br /&gt;
         return _val;&lt;br /&gt;
 } &lt;br /&gt;
 /* For OCEOS &lt;br /&gt;
 #endif&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If bcc_inline.h is not modified traps may be left disabled or in REX mode an illegal opcode trap is generated. [GRLIB]&lt;br /&gt;
&lt;br /&gt;
== Mode selection and control ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library with header files for applications wishing to use it. There are two primary modes of operation on the GR716 as follows:&lt;br /&gt;
* SPARC V8 32-bit Mode &amp;lt;/br&amp;gt; 32-bit mode is the standard instruction word size on the SPARC V8. An OCEOS object library is provided for 32-bit mode (gcc &amp;amp; llvm)&lt;br /&gt;
* REX 16-bit mode &amp;lt;/br&amp;gt; REX mode allows the GR716 to execute 16-bit instructions. Applications running in rex mode occupy a smaller memory footprint. The compiler option -mrex should be used and -Oz for the smallest footprint.&lt;br /&gt;
&lt;br /&gt;
It is an application design choice as to which mode is used.&lt;br /&gt;
&lt;br /&gt;
== Normal operations ==&lt;br /&gt;
&lt;br /&gt;
This section describes the OCEOS directives used to in most applications. See file asw.c for example.&lt;br /&gt;
&lt;br /&gt;
The calls to get OCEOS running are:&lt;br /&gt;
&lt;br /&gt;
# application_init – uses oceoc_init to Initialise fixed data and start system time and log&lt;br /&gt;
# oceos_task_create - Create task setting priority, no of jobs, ..etc.&lt;br /&gt;
# oceos_init_finish – Initilise dynamic data area&lt;br /&gt;
# oceos_start – Start the scheduler and pass control to first task&lt;br /&gt;
&lt;br /&gt;
After steps 1 to 4 above tasks implement application functionality. If mutexes, semaphores, dataqs and/or timed actions are required they also are created at step 2. &amp;lt;/br&amp;gt;&lt;br /&gt;
Note: it is mandatory to create the number of mutexes, semaphores, and dataqs declared otherwise oceos_init_finish() will return an error.&lt;br /&gt;
&lt;br /&gt;
=== application_init() ===&lt;br /&gt;
&lt;br /&gt;
[[File:application_init.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create (…) ===&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
oceos_task_create prepares a task for execution. In the case above the parameters are:&lt;br /&gt;
* t_setup is an integer setup in the enumerated type in oceos_config.h. t_setup is used to identify this task to OCEOS thereafter. &lt;br /&gt;
[[File:enum_task_name.jpg]]&lt;br /&gt;
* 3 is the priority allocated to this task. 1 is the highest and 254 the lowest priority&lt;br /&gt;
* 3 is the priority threshold. The scheduler will only allow tasks higher than this priority to pre-empt task t_setup.&lt;br /&gt;
* 1 is the maximum number of jobs for task t_setup. 15 is the maximum number of jobs that can be ready-to-run for any task.&lt;br /&gt;
* 0 indicating that floating point is not used by this task. Enabling floating point for a task causes the scheduler to store all floating point registers on the stack when the job is pre-empted. If the job is not using floating point this causes inefficiency.&lt;br /&gt;
* 1 causes the task to be enabled on when oceos is started.&lt;br /&gt;
* setup_start is the name of the function to be executed for this task. The code for setup_start is in asw.c and the function declared in asw.h.&lt;br /&gt;
[[File:setup_start.jpg]]&lt;br /&gt;
* setup_end is the function called when task t_setup terminates.&lt;br /&gt;
[[File:setup_end.jpg]]&lt;br /&gt;
* 0 instructs the scheduler that there is no maximum execution time for this task. If a value (in microseconds) is specified the scheduer will raise an error if the task exceeds this execution time.&lt;br /&gt;
* 0 instructs the scheduler that there is no minimum time between executions of this task. If a time in microseconds is specified the scheduler will raise an error if this value is violated.&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish() ===&lt;br /&gt;
This function must be called before OCEOS is started. It completes the initialisation of OCEOS data for the application.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_init_finish.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_start() ===&lt;br /&gt;
&lt;br /&gt;
This function starts task scheduling in OCEOS. It should never return from this function.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters passed to oceos_start are:&lt;br /&gt;
* fixed_data is a pointer to the start of the fixed data area. It is declared in oceos_config.c.&lt;br /&gt;
* t_setup is the ID of the task to be set executing when OCEOS starts (in oceos_config.h).&lt;br /&gt;
* Optional pointer that will be passed to the task started, here t_setup.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive starts an instance of a task, called a job in OCEOS. In this case start means puts an instance of the task, a job, on the ready-to-run queue, and performs a reschedule.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; If it is the highest priority job ready-to-run, it will be set running by the scheduler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The parameters passed to it are the task ID and a pointer. It returns an integer indicating the status of the call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many cases the first task to be run by OCEOS will perform application initialisation and then start the other application tasks including the idle task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex. It must be called before oceos_init_finish(). Parameters passed are the mutex ID and the priority ceiling for the mutex.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling is the priority of the highest task that uses the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note that the user must determine this priority ceiling as part of the application design. &lt;br /&gt;
OCEOS relies on the developer to specify the correct priority ceiling.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive assigns the mutex to the calling job. It should always be successful because a job should only be set running if the mutex is available to it.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_wait.jpg]]&lt;br /&gt;
&lt;br /&gt;
The mutex ID is the only parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive releases a mutex from a job. It will cause a reschedule and if a higher priority job has been waiting on the mutex it will start causing this job to be pre-empted.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The only parameter to the directive is the mutex ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a counting semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_create2.jpg |700px]]&lt;br /&gt;
&lt;br /&gt;
* Semaphore ID (0 to 62)&lt;br /&gt;
* Maximum No of permits (1 to 4094)&lt;br /&gt;
* Starting number of permits (1 to 4094)&lt;br /&gt;
* Maximum number of jobs on this semaphore queue (1 to 254)&lt;br /&gt;
* Whether timeout is used in oceos_sem_wait_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameter is:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted.&lt;br /&gt;
If a timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart_timeout.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer, long long)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive increments (signals) the specified semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_sem_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The semaphore ID is the sole parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a data queue with specified ID&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_create2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Data Queue Size (1 to 255)&lt;br /&gt;
* Data Queue maximum number of pending jobs (1 to 255)&lt;br /&gt;
* Data Queue roll-overs enable/disable (0 or 1)&lt;br /&gt;
* Whether timeout is used in oceos_dataq_read_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A timeout in microseconds can be set, after which the task will not be restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart_timeout2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive puts a pointer on the specified data queue.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_dataq_write.jpg]]&lt;br /&gt;
&lt;br /&gt;
Parameters are :&lt;br /&gt;
* Data queue ID (0 to 62)&lt;br /&gt;
* Pointer to be put on queue (void *ptr)&lt;br /&gt;
&lt;br /&gt;
== Normal termination ==&lt;br /&gt;
&lt;br /&gt;
It is not normal for OCEOS to terminate. Application tasks usually continue to execute without stopping. If all tasks terminate the system goes to sleep mode and only an interrupt can restart activity.&lt;br /&gt;
&lt;br /&gt;
== Error conditions ==&lt;br /&gt;
&lt;br /&gt;
Error conditions are handled in 4 different ways by OCEOS as follows:&lt;br /&gt;
* Directive return codes allowing application take appropriate action&lt;br /&gt;
* The System Log keeps a record of problems and when they occurred&lt;br /&gt;
* The System State variable indicates the current state of OCEOS&lt;br /&gt;
* The watchdog provides a fallback reset in unpredictable situations&lt;br /&gt;
&lt;br /&gt;
=== Directive return codes ===&lt;br /&gt;
&lt;br /&gt;
OCEOS is driven by directives described in the Reference section below. All directives return a status to be checked by the application. The directive return status is either success or a code indicating why it failed. The table below is taken from oceos.h. It is the responsibility of the application to take appropriate action if a directive call fails.&lt;br /&gt;
&lt;br /&gt;
[[File:Enum_directive_status2.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== The System Log ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;When a problem arises, either in application code or in OCEOS itself, it is useful to have a record of &amp;lt;/p&amp;gt;&lt;br /&gt;
# '''when''' it happened&lt;br /&gt;
# '''what''' kind of problem it was&lt;br /&gt;
# '''where''' it happened.&lt;br /&gt;
&amp;lt;p&amp;gt;The primary purpose of the System Log is to provide this ‘when’, ‘what’, and ‘where’ information.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It does so as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''when''':   the low 32-bits of the system time are automatically recorded when a log entry is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''what''':   an 8-bit number allows 256 different types of entry be specified. Half of these entry types (0x80 to 0xff) are reserved for internal us in OCEOS. The other 128 entry types (0 to 0x7f) are assigned their meanings by the application. (An OCEOS internal code reserved for that purpose is used if an application attempts to use an OCEOS internal code.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''where''':  a 24-bit number is included in each log entry. OCEOS itself uses this to indicate the OCEOS function where the log entry call was made and other information. Application code can use this number in whatever way is appropriate for the application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The log is located in the log area. This area starts at an address specified by the application developer, begins with a 32-bit constant sentinel value followed by a 32-bit count of the number of 32-bit words making up the area (including the sentinels) and ends with a 32-bit constant sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As frequent access to the log area is not likely to be needed the log area can be located in memory external to the GR716. The log area contents will then usually be preserved across system resets, and across system power on/off cycles if the external memory is non-volatile.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The log is structured as a circular buffer, with its read and write indices also stored in the log area. It is set up initially by oceos_init(). This does not overwrite the data currently in the log but resets the read and write indices to be equal and as far as can be determined after the most recent log entry. As the log indices are equal the log now appears empty when an attempt to read it in the usual way is made, but a special directive allows the application program read the data at any position in the log. Another directive allows the application reset all log entries.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Any system that uses OCEOS must have a system log. The number of entries in the log is specified in the system configuration structure, and must be within the specified range or 0, in which case a default value is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The header file oceos.h gives the structure of the log area and the values of the associated constants.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 struct log_entry{&lt;br /&gt;
  U32_t time32;&lt;br /&gt;
  unsigned int entry_type :8;&lt;br /&gt;
  unsigned int entry_comment :24;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
 * Log entry types used when creating a log entry (8 bits, from 0 to 255 only)&lt;br /&gt;
 */&lt;br /&gt;
 enum LOG_ENTRY_TYPE{&lt;br /&gt;
  LOG_SYS_OK = 0x80U,&lt;br /&gt;
  LOG_NULL_FATAL,&lt;br /&gt;
  LOG_OCEOS_ABORT,&lt;br /&gt;
  LOG_INVALID_SYSTEM_STATE,&lt;br /&gt;
  LOG_LOG_NOT_VALID_ENTRY,&lt;br /&gt;
  LOG_STATUS_INVALID,&lt;br /&gt;
  LOG_NULL_POINTER,&lt;br /&gt;
  LOG_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_FREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_UNFREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_RESET_FAIL,&lt;br /&gt;
  LOG_TIME_SCALER_FAIL,&lt;br /&gt;
  LOG_TIME_RELOAD_FAIL,&lt;br /&gt;
  LOG_TIME_COUNTER_FAIL,&lt;br /&gt;
  LOG_TIME_CONTROL_FAIL,&lt;br /&gt;
  LOG_TIME_POINTER_NULL,&lt;br /&gt;
  LOG_TIME_POINTER_LOW_NULL,&lt;br /&gt;
  LOG_TIME_START_FAIL,&lt;br /&gt;
  LOG_FIXED_INIT_FAIL,&lt;br /&gt;
  LOG_DYNAMIC_INIT_FAIL,&lt;br /&gt;
  LOG_INIT_TASK_START_FAIL,&lt;br /&gt;
  LOG_DEADLINE_MISSED,&lt;br /&gt;
  LOG_TASK_DISABLED,&lt;br /&gt;
  LOG_TASK_ENABLED,&lt;br /&gt;
  LOG_JOB_INVALID,&lt;br /&gt;
  LOG_JOB_NONE_FREE,&lt;br /&gt;
  LOG_JOB_NOT_EXECUTING,&lt;br /&gt;
  LOG_JOB_NOT_ACTIVE,&lt;br /&gt;
  LOG_READYQ_TOO_BIG,&lt;br /&gt;
  LOG_READYQ_SENTINEL_BAD,&lt;br /&gt;
  LOG_READYQ_FULL,&lt;br /&gt;
  LOG_READYQ_EMPTY,&lt;br /&gt;
  LOG_READYQ_PUT_DISABLED_TASK,&lt;br /&gt;
  LOG_READYQ_PUT_FAIL,&lt;br /&gt;
  LOG_READYQ_REMOVE_DONE,&lt;br /&gt;
  LOG_READYQ_REMOVE_FAIL,&lt;br /&gt;
  LOG_PARAM_BAD_ID,&lt;br /&gt;
  LOG_PARAM_BAD_TIME,&lt;br /&gt;
  LOG_PARAM_ACTION_MISSING,&lt;br /&gt;
  LOG_PARAM_JOB_MISSING,&lt;br /&gt;
  LOG_MUTEX_BAD_CEILING,&lt;br /&gt;
  LOG_MUTEX_ALREADY_HELD,&lt;br /&gt;
  LOG_MUTEX_ALREADY_FREE,&lt;br /&gt;
  LOG_MUTEX_WRONG_JOB,&lt;br /&gt;
  LOG_MUTEX_NESTING_BAD,&lt;br /&gt;
  LOG_MUTEX_EXIT_HOLDING,&lt;br /&gt;
  LOG_SEMAPHORE_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_SEMAPHORE_MAX_ALREADY_REACHED,&lt;br /&gt;
  LOG_SEMAPHORE_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_TIMED_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_TRANSFER_READYQ_FAIL,&lt;br /&gt;
  LOG_DATAQ_FULL,&lt;br /&gt;
  LOG_DATAQ_EMPTY,&lt;br /&gt;
  LOG_DATAQ_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_DATAQ_PENDING_QUEUE_FULL,&lt;br /&gt;
  LOG_DATAQ_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_DATAQ_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_DATAQ_TIMED_JOB_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_NULL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_STOP_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_NOT_INIT,&lt;br /&gt;
  LOG_TIMED_ACTION_INT_REG_FAILED,&lt;br /&gt;
  LOG_TIMED_ACTION_INVALID,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_INDEX,&lt;br /&gt;
  LOG_TIMED_ACTION_MISSED,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_FULL,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_EMPTY,&lt;br /&gt;
  LOG_TIMED_ACTION_PUT_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_JOB_ID,&lt;br /&gt;
  LOG_TIMED_ACTION_DO_FAIL,&lt;br /&gt;
  LOG_SYSTEM_ERROR,&lt;br /&gt;
  LOG_TIME_BSP_SYSFREQ_NULL,&lt;br /&gt;
  LOG_SEMAPHORE_TIMEOUT_NOT_INIT,  &lt;br /&gt;
  LOG_DATAQ_TIMEOUT_NOT_INIT, &lt;br /&gt;
  LOG_TIMED_ACTION_START_WHILE_RUNNING,&lt;br /&gt;
  LOG_INT_HANDLER_IS_NULL,&lt;br /&gt;
  LOG_SET_OCEOS_TRAP_HANDLER_FAILED,&lt;br /&gt;
  LOG_INT_CALLED_NO_INIT,&lt;br /&gt;
  LOG_FAILED_SET_INT_PRIO,  &lt;br /&gt;
  LOG_FAILED_PENDSV_INIT,&lt;br /&gt;
  LOG_SYS_TIME_NOT_INIT    &lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_add_entry(&lt;br /&gt;
 enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
 const unsigned int // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_remove_entry(struct log_entry * const);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_get_indexed_entry(&lt;br /&gt;
 const unsigned int,&lt;br /&gt;
 struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The System State variable ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/p&amp;gt;OCEOS maintains a system state variable which shows the current state of the system. States are shown below. If the system state deviates from normal (value 0) the user defined function oceos_on_error(..) is called by OCEOS. The source code for this function is located config.c and should be written by the application developer to take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directives oceos_system_state_get and oceos_system_state_set are provided to allow the application to access the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void oceos_on_error(void* ptr) { // Application dependent error handling code should be included here&lt;br /&gt;
 return;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
 * The 32-bit system state variable indicates the current system state&lt;br /&gt;
 */&lt;br /&gt;
 #define STATUS_NORMAL 0u // System State Normal&lt;br /&gt;
 #define STATUS_EDAC_INTERNAL 1u // Uncorrectable error in internal memory&lt;br /&gt;
 #define STATUS_EDAC_EXTERNAL 2u // Uncorrectable error in external memory&lt;br /&gt;
 #define STATUS_MEM_PROT_1 4u // Invalid access memory protection unit 1&lt;br /&gt;
 #define STATUS_MEM_PROT_2 8u // Invalid access memory protection unit 2&lt;br /&gt;
 #define STATUS_DISABLED_TASK_START 0x10u // An attempt to start a disabled task&lt;br /&gt;
 #define STATUS_TASK_JOB_LIMIT_OVER 0x20u // An attempt to execute a task when its jobs limit is already reached.&lt;br /&gt;
 #define STATUS_JOB_OVER_TIME 0x40u // Job time from creation to completion exceeds allowed maximum for a task.&lt;br /&gt;
 #define STATUS_JOB_INTERVAL_SHORT 0x80u // Minimum time between job creations is less than the allowed minimum for task&lt;br /&gt;
 #define STATUS_READYQ_FULL 0x100u // Ready queue unable to accept job as result of being full&lt;br /&gt;
 #define STATUS_MUTEX_ALREADY_HELD 0x200u // Mutex wait() when mutex already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_HELD 0x400u // Mutex signal() when not already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_RETURNED 0x800u // Mutex not returned before job terminates&lt;br /&gt;
 #define STATUS_SEMAPHORE_JOBS_FULL 0x1000u // Attempt to add job to semaphore pending list when list full&lt;br /&gt;
 #define STATUS_DATAQ_FULL 0x2000u // Data queue write when queue already full&lt;br /&gt;
 #define STATUS_DATAQ_JOBS_FULL 0x4000u // Attempt to add job to queue pending list when list full&lt;br /&gt;
 #define STATUS_TIMED_JOBS_FULL 0x8000u // Timed jobs queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_JOB_LATE 0x10000u // Timed jobs queue late job transfer to scheduler&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_FULL 0x20000u // Timed output queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_LATE 0x40000u // Timed output late&lt;br /&gt;
 #define STATUS_BAD_LOG 0x80000000u // System Log corruption&lt;br /&gt;
 #define STATUS_INVALID 0xffffffffu // Invalid system state&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The watchdog ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 provides watchdog functionality (ref: GR716 Advanced Data Sheet and User’s Manual). OCEOS provides functions to allow applications to use this watchdog functionality (see section 10 for more details). It is expected that OCEOS applications using the watchdog have a low priority task to continually reset the watchdog timer using the directive oceos_system_watchdog_reset(..). If the watchdog reaches its timeout value this is an indication that a severe error has occurred and a hardware reset is generated by the watchdog unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application when rebooted can optionally check the system log, and last system state to determine the cause of the watchdog reboot and take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hardware errors ===&lt;br /&gt;
&lt;br /&gt;
Hardware errors can come from a number of sources including the following:&lt;br /&gt;
* Uncorrectable memory errors&lt;br /&gt;
* Memory protection violations&lt;br /&gt;
* Brown-out or low power&lt;br /&gt;
The OCEOS philosophy to dealing with these and other hardware faults causing interrupts is to provide directives enabling the application to take appropriate actions. OCEOS directives available for application recovery are:&lt;br /&gt;
* oceos_interrupt_handle_register This directive may be used to setup application recovery interrupt service routines.&lt;br /&gt;
* oceos_exit This directive may be called to exit OCEOS back to the application for appropriate recovery actions.&lt;br /&gt;
* oceos_log_get_indexed_entry This directive may be used as part of the application fault analysis.&lt;br /&gt;
* oceos_system_state_get This action allows the application obtain the system status to determine appropriate recovery action.&lt;br /&gt;
&lt;br /&gt;
=== Overload and system failure ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overloads and system failure are different but have some common features. Both can lead to an unexpected system restart, and to the question ‘what caused that?’. Both can sometimes be anticipated if warning signs are noticed. It may even be possible to avoid them by taking appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Some thoughts and suggestions about them and OCEOS follow below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Overload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overload generally refers to insufficient CPU time to handle a situation.&lt;br /&gt;
Can also be a memory shortage, for example insufficient stack space.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;A task missing a soft deadline - needs to be noted&amp;lt;/li&amp;gt; &lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;A task missing a hard deadline - may be catastrophic&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Watchdog timeout - hardware reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inability to start a task due to memory shortage&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Interrupts more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task pre-empted more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Tasks start requests more frequent than expected&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inappropriate allocation of task priorities&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;One or more tasks using more than the expected CPU time (should not happen)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Holding one or more mutexes for too long&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Using mutexes in a non-nested manner&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Insufficient stack space&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;(With OCEOS unbounded priority inversion cannot occur.)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;(With OCEOS chained blocking cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;(With OCEOS deadlocks cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Information available for comparison to expected values to detect potential overload'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Task maximum duration – job creation time to termination time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task maximum CPU time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Task minimum time between start requests&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Task number of times pre-empted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Task maximum current jobs for a task&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Watchdog timer nearly timed out when reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Stack pointer approaching limit of allowed range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Et alia&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Disable certain interrupts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Disable a task or tasks&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Kill currently executing job&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== System failure ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;System failure generally refers to the CPU ceasing to execute instructions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Can also be a reference to the operating system (OCEOS) having to exit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Usually associated with hardware problems, but software can do it too.&amp;lt;/p&amp;gt;&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;OCEOS exit (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;CPU stops execution (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;A subsequent restart (hopefully)&amp;lt;/li&amp;gt;&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Critical OCEOS data corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Un-correctable memory error&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Memory hardware failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Power failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Environment more demanding than design anticipated causing hardware problems&amp;lt;/li&amp;gt;&lt;br /&gt;
''Warning signs that can indicate something wrong at system level'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Sentinels on OCEOS critical data areas corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Stack pointer approaching limit of range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Corrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Uncorrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Voltage levels - brown out detection interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Use EDAC scrubber units to continually regenerate all RAM&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Use MEMPROT unit to restrict OCEOS fixed data write access to the scrubber only&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Current System State ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Before discussing reports it seems appropriate to describe how the system state is stored and accessed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - OCEOS and the Application software'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For OCEOS this is given by its fixed data area, its dynamic data area, and its log data area. Also by some heap items and the stack and registers, including the PC. The latter are also relevant to the application state.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The locations and sizes of three OCEOS areas are determined by the application. Their lay-outs are known. A meta-data structure in the fixed area provides pointers to the principal fields within each data area and simplifies access by OCEOS and by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The three OCEOS areas are available for inspection after OCEOS exits and before it restarts as well as while it is running. This helps after a restart in assessing what went wrong, as well as allowing an application check for lurking problems while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(OCEOS does not allow tasks etc. be created once scheduling has begun, and as a result does not need to use dynamic memory allocation. The memory areas it uses can thus be fixed in advance, their locations and sizes determined by the application.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The task information items mentioned above are automatically updated by OCEOS in the dynamic data area and can be accessed by the application at any time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system state variable contains flags that indicate a certain problem has occurred. It is automatically updated by OCEOS using ‘OR’ to avoiding losing information, typically a user defined function is called to deal with the problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two sets of flags are kept as part of the system state variable. One accumulates indicators of all problems that have occurred, and typically is reset by the application only after a restart. The other indicates current problems, and typically is reset by the user defined problem handling function.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system log records when, what, and in some cases where something occurred. It is automatically written to by OCEOS in certain conditions and can also be read and written by the application. (Codes for what from 0x80 to 0xff are reserved for use by OCEOS, codes 0 to 0x7f are available for use by the application. At present only 24 bits are used to indicate where, this can be expanded to e.g. include the PC or stack pointer.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;At present the log area contains the system state variable as well as the system log. The system state variable could equally well be stored in the dynamic data area.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - Hardware'':&lt;br /&gt;
&lt;br /&gt;
Registers&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 has 504 32-bit IU registers, organized in 31 windows. In addition there are the usual processor registers PC, SP, Y, %psr, %wim and %tbr, and ancillary state registers %asr16, %asr17, %asr20, %asr22-23, %asr24-31. There are also 32 floating point registers, each 32-bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Other units with registers that have a key role in determining the current hardware state include the interrupt controller, the clock gating units, the EDAC and memory scrubber units, and the statistics unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;After a reset registers may have been automatically reset to some initial value and their previous content lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EDAC&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The internal data and instruction RAMs and the external RAM have individual EDAC and scrubber units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Normally the scrubber units will be configured to cycle through the memory, reading each location and writing it back if an error is detected, thus helping reduce the likelihood of a double bit error.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a double bit error is detected, the scrubber units can be configured to halt with the current address in a scrubber register and generate an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The two scrubbers for the internal memory each have a 4-bit counter (ECNT) for the number of single bit errors corrected. This can be reset by writing 0 to it. Correctable errors do not cause an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The external scrubber unit counts both correctable and un-correctable errors it has encountered, and allows thresholds be set for each of these so that an interrupt is generated if either threshold is exceeded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;EDAC errors give rise to an interrupt on interrupt line 63 which is mapped by default to interrupt 19. A handler for this interrupt needs to be put in place by the ASW as what should be done depends on the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;if set up appropriately the EDAC system can also be used to get an indication of background radiation levels by periodically checking the number of single bit errors that have been corrected in a given time period. Again should be done, if required, by the ASW.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reporting====&lt;br /&gt;
&lt;br /&gt;
Two main types of report&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current system state, including checking for potential problems&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;System state when a problem has occurred&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Non-fatal problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Reporting the Current System State''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As all OCEOS data is readily available, and the application itself is running in kernel/supervisor mode and is able to access all registers, there is no obvious help required from OCEOS to enable an application analyse the current state of the system whenever it wishes and report on this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A different question is what conditions OCEOS itself should monitor and bring to the attention of the application so that the application can take action and perhaps prevent the emergence of a problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The standard OCEOS mechanism for bringing an anomaly to the attention of the application is to call a user defined problem handling function after updating the system state variable and making a system log entry.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
The question then becomes in what circumstances OCEOS should do this.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS will always notify the application if it detects a problem such as a task using a mutex whose ceiling is lower than the task’s priority (an application configuration error), or a task exiting while holding a mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, a deadline for the task (number of microseconds after request to start by which it should have completed) can be specified. OCEOS can automatically notify the application if a task has missed its deadline. Or alternatively, if the time when a task completed was dangerously close to its deadline.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, an expected minimum time between task start requests can be specified. OCEOS can automatically notify the application if a start request occurs sooner than this, or alternatively if the time between start requests was too close to the expected value.??&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
OCEOS can check the state of the system when it does a context switch, or when any of its directives are used, or when it performs a timed action. (Unlike many operating systems OCEOS does not depend on a regular timer tick interrupt.)&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
''Reporting System State after a problem has occurred''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the problem is non-fatal, so that OCEOS can continue, when OCEOS detects the problem it will call the user defined problem handling function after updating the system state variable and system log.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU continues to function but OCEOS cannot continue, e.g. due to an OCEOS data area being corrupted by the application, OCEOS will exit. The application can consult the OCEOS data areas and various hardware registers to determine why OCEOS had to exit. It can then restart OCEOS.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU itself must shut down, and warning is given of this before it must happen by e.g. a brown-out detector, then two reports are involved&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a short death report for use before the CPU shuts down&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a long death report put together after the system restarts&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Usually generated in an interrupt handler (e.g. brown-out detected)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The type of problem is identified by the interrupt caused&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS does not seem to have any role in reading registers, whether in EDAC or scrubber units or elsewhere, simpler to just read them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Same applies to system time if needed, just requires a timer register read.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current task and job (equivalent of thread) can be stored by OCEOS in same area as OCEOS system state variable to make both readable as one block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Other items that might be stored in this block by OCEOS include&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;system priority ceiling (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;interrupt nesting level (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on ready queue (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;current number of mutexes held (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on counting semaphore pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on data queue pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of actions on timed actions queue (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The interrupt handler might also store items in the block, e.g.&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;PC when the interrupt was called&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Stack pointer&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;EDAC/scrubber registers&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS can keep the block up to date each time a new job begins executing (not done at present but no problem). But just what should the block include??&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The block data will be preserved across resets depending on the memory used. If this is non-volatile it will be preserved across power fail/restore cycles, and accessible in creating the long death report after restart.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Don’t think OCEOS has a role in relation to the line or function where the error happened (using GCC/LLVM predefined macros, such as __LINE__)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;What other OCEOS summary information if any should kept in the quick death report data block? (The detailed information on task times etc are accessible but probably too much for the short death report.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; The application chooses the memory to be used for the OCEOS dynamic area and for the OCEOS log area. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If both of these are non-volatile a very detailed description of the state of the system when the reset occurred is available to the application after the restart and can be used by it to generate a report before it restarts OCEOS (which will overwrite the dynamic area).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the short death report block is stored in one of these areas it will also be available.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the two areas are volatile the above will still be true but only for resets that did not involve power failure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the areas are in GR716 internal memory the GR716 boot sequence needs to be taken into account. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; After a reset it is likely that register contents, whether in the CPU or elsewhere, will not have been preserved. This is true a fortiori if the reset was caused by a power failure. Critical register information, such as the PC and stack pointer, will need to be captured in the quick death report data block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Changing the default trap handler====&lt;br /&gt;
&lt;br /&gt;
The default trap handler provided by BCC may be changed by modifying trap_table_svt_tables.S provided with BCC. The default BCC trap handler __bcc_trap_table_svt_bad should be replaced with the ASW trap handler or the OCEOS default trap handler (__oceos_default_trap_handler) provided in the example applications (shown below). The application should now be recompiled and linked with the new trap_table_svt_tables.S. When application starts, all trap handlers will be in memory ready for use by the application.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /** &lt;br /&gt;
 * OCEOS default trap handler. &lt;br /&gt;
 */ &lt;br /&gt;
 void __oceos_default_trap_handler () &lt;br /&gt;
 { &lt;br /&gt;
   U32_t tt; &lt;br /&gt;
   __asm__ volatile ( &amp;quot;mov %%tbr, %0&amp;quot; : &amp;quot;=&amp;amp;r&amp;quot; (tt));&lt;br /&gt;
   tt = (tt &amp;amp; 0xff0) &amp;gt;&amp;gt; 4; &lt;br /&gt;
   // Log ERROR and return &lt;br /&gt;
   oceos_log_add_entry(LOG_SYSTEM_ERROR, tt); &lt;br /&gt;
   // Update System Variable &lt;br /&gt;
   U32_t current_state = oceos_system_state_get(); &lt;br /&gt;
   current_state |= STATUS_SYSTEM_ERROR; &lt;br /&gt;
   oceos_system_state_set(current_state); &lt;br /&gt;
   __asm__ volatile (&amp;quot;restore&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;jmp %l2&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;rett %l2 + 0x4&amp;quot;); &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Context Switch Logging ==&lt;br /&gt;
&lt;br /&gt;
'''Basic approach:'''&lt;br /&gt;
&lt;br /&gt;
If enabled, each time a context switch or interrupt occurs four 32-bit words are added to the context switch log.&lt;br /&gt;
&lt;br /&gt;
The first of these describes the type of switch and also gives the current window pointer (CWP) and the low 8 bits of the high 32 bits of the 64-bit system time when the switch occurred.&lt;br /&gt;
The second gives the 32-bit system time in microseconds at which the switch occurred.&lt;br /&gt;
&lt;br /&gt;
The third gives the start delay if a task is being started, otherwise a signed int giving the remaining time until the deadline or INT_MAX if the task has no deadline, a negative value gives by how much the deadline has been missed.&lt;br /&gt;
The fourth gives the current system stack pointer. &lt;br /&gt;
&lt;br /&gt;
The user specifies the number of entries in the context switch log in the application configuration. This size is given as a number in the range 3 to 12, resulting in from 2^3 to 2^12 entries. If a size outside this range is specified no context switch log is present (no header and no entries).&lt;br /&gt;
&lt;br /&gt;
If valid the size is stored in sysMetaPtr-&amp;gt;CS_log_entries_base2. If invalid this holds 0, CS logging is off.&lt;br /&gt;
&lt;br /&gt;
'''CS Log Structure:'''&lt;br /&gt;
&lt;br /&gt;
CS Header followed by circular buffer, each buffer entry four 32-bit words.&lt;br /&gt;
&lt;br /&gt;
''Switch information (first word):''&lt;br /&gt;
&lt;br /&gt;
*8 bits high time bits (31 to 24)&lt;br /&gt;
*5 bits CWP  (23 to 19)							  	      &lt;br /&gt;
*1 bit (18) switch type,  0=&amp;gt; starting, 1 =&amp;gt; interrupt or ending 				      &lt;br /&gt;
*1 bit (17) ‘from’ ID type, 0=&amp;gt; from task, 1 =&amp;gt; from interrupt				      &lt;br /&gt;
*1 bit (16) ‘to’ ID type, 0 =&amp;gt; to task, 1 =&amp;gt; to interrupt					      &lt;br /&gt;
*8 bits (15 to 8) ID of task/interrupt from which switching				      &lt;br /&gt;
*8 bits (7 to 0) ID of task/interrupt to which switching&lt;br /&gt;
 &lt;br /&gt;
:TASK_ID_INVALID (0xff) is used to indicate switching to or from the scheduler itself. 	  The interrupt ID 0 is not expected to occur, used as TO when CPU put to sleep	     Initialised by oceos_start() to 0x0000ffff (invalid as scheduler doesn’t switch to itself).&lt;br /&gt;
&lt;br /&gt;
''Context switch time word (second word):''&lt;br /&gt;
&lt;br /&gt;
:Low 32 bits of the time at which switch happened. The next 8 bits of the 64-bit system time are given in the switch information word, giving an overall 40-bit time value. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''Start wait time / deadline time margin word (third word):''&lt;br /&gt;
&lt;br /&gt;
:When first starting a task, the delay between the start request and execution beginning. Otherwise a signed int giving remaining time until deadline or 0x7fffffff if no deadline. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''System stack pointer (fourth word):''&lt;br /&gt;
&lt;br /&gt;
:System stack pointer when switch was made. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
'''Storage:'''&lt;br /&gt;
&lt;br /&gt;
Stored in log area immediately after last system log entry and before END_SENTINEL for log area.&lt;br /&gt;
&lt;br /&gt;
Space needed for CS log is included in log area size recorded at the start of the log area.&lt;br /&gt;
&lt;br /&gt;
Number of CS log entries is 2^size unless size is invalid, in which case no storage is used.&lt;br /&gt;
&lt;br /&gt;
If sysMetaPtr-&amp;gt;CS_log_entries_base2 is outside the allowed range (typically 0) no context switch logging is done. The CS header is not present, END_SENTINEL is at that position instead.&lt;br /&gt;
&lt;br /&gt;
== Recover runs ==&lt;br /&gt;
&lt;br /&gt;
The previous section describes the error diagnostic facilities provided by OCEOS. The recovery procedure is the responsibility of the application. In the worst case a system reset can be initiated by the application. The table below shows some failure modes and recommended actions to recover.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;text-align:left;&amp;quot;| SFMEA ID&lt;br /&gt;
! Failure cause&lt;br /&gt;
! Recommended action&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0010&lt;br /&gt;
|ASW sets up a non-schedulable set of tasks&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0020&lt;br /&gt;
|ASW sets up a task that may demands excessive CPU or Memory resources&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom and map file to view memory usage&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0040&lt;br /&gt;
|Human error in OCEOS code&lt;br /&gt;
|Email details to support@ocetechnology.com&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0045&lt;br /&gt;
|Divide by zero occurs in OCEOS or in ASW.&lt;br /&gt;
|ASW to implement user defined trap&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0060&lt;br /&gt;
|Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW should use EDAC scrubber to correct error and report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0070&lt;br /&gt;
|Single Event Upset, permanent (burnt bit) in RAM&lt;br /&gt;
|ASW to refactor memory location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0080&lt;br /&gt;
|Single Event Upset, temporary in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to rewrite PROM location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0090&lt;br /&gt;
|Single Event Upset, permanent (burnt-proton impact etc) in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to set indicator to boot from backup image&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0100&lt;br /&gt;
|Double bit Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW to initiate warm or cold restart&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0110&lt;br /&gt;
|RAM memory corruption by any reason e.g. incorrect write address&lt;br /&gt;
|ASW dependent but warm or cold restart are options&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.16FM-0&lt;br /&gt;
|continuous false alarm&lt;br /&gt;
|ASW to reduce alarm check interval amd mark as ignore&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0130&lt;br /&gt;
|deadlock occurs&lt;br /&gt;
|Deadlock cannot occur from OCEOS directives&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0140&lt;br /&gt;
|clock corrupted, frozen or rate drifts (HSIA crystal failure)&lt;br /&gt;
|ASW to trigger watchfod restart and report issue&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0150&lt;br /&gt;
|output before required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0160&lt;br /&gt;
|output after required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=707</id>
		<title>OCEOS Operation</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=707"/>
		<updated>2021-10-01T12:34:30Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* The System State variable */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Operations basics =&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library, header files(s), and application source files that can be compiled and linked with the standard BCC gcc or clang tools and libraries to provide a real-time multitasking application. OCEOS uses BCC library calls for some system functions. These functions are provided in the BCC board support package for the GR716. The minimum memory footprint for OCEOS is shown in the table below. Core modules occupy less than 10K bytes.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_size.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Operations manual =&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is structured as a set of managers each providing OCEOS service calls. &amp;lt;/br&amp;gt;&lt;br /&gt;
The activities supported by these managers are: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|''''' Initialization manager ''''':&lt;br /&gt;
|initializing the hardware and OCEOS itself&lt;br /&gt;
|-&lt;br /&gt;
|''''' Task manager ''''':&lt;br /&gt;
|handling tasks and jobs, including scheduling&lt;br /&gt;
|-&lt;br /&gt;
|''''' Interrupt manager ''''':&lt;br /&gt;
|setting up trap handlers&lt;br /&gt;
|-&lt;br /&gt;
|''''' Clock manager ''''':&lt;br /&gt;
|providing time of day, dates, and alarms&lt;br /&gt;
|-&lt;br /&gt;
|''''' Timer manager ''''':&lt;br /&gt;
|interval timing and alarms, timed outputs and jobs&lt;br /&gt;
|-&lt;br /&gt;
|''''' Mutex manager ''''':&lt;br /&gt;
|mutual exclusion management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Semaphore manager ''''':&lt;br /&gt;
|counting semaphore management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Data queue manager ''''':&lt;br /&gt;
|data queue management&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The directives provided by these managers are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== Set‐up and initialisation ==&lt;br /&gt;
&lt;br /&gt;
Setup for the use of OCEOS requires the user to prepare the development environment.&lt;br /&gt;
At a minimum this requires the installation for compilers, debug tool, editors, …etc.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
=== DMON OCEOS Support===&lt;br /&gt;
:OCE added OCEOS support to DMON to help user in debugging application software. Detailed manual and available functionality can be found [[DMON_OCEOS_Support|'''here''']].&lt;br /&gt;
&lt;br /&gt;
[[File:Cpu_load_main.png|600px|Cpu Load View]] [[File:Cpu_profile_main.png|600px|Cpu Profile View]]&lt;br /&gt;
&lt;br /&gt;
=== Files provided with OCEOS ===&lt;br /&gt;
&lt;br /&gt;
Unpack the OCEOS software into an appropriate folder on the computer. The folders are as follows:&lt;br /&gt;
&lt;br /&gt;
[[File:unzip_folders.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Documentation OCEOS User Manual and Quick Reference.&lt;br /&gt;
* include Include files required by the application&lt;br /&gt;
* OCEOS_GCC_LIB oceos.a object library for applications to be built with gcc&lt;br /&gt;
* OCEOS_LLNM_LIB oceos.a object library for applications to be built with llvm (32-bit)&lt;br /&gt;
* OCEOS_LLVM_REX_LIB oceos.a object library for applications to be built with llvm (16-bit REX mode)&lt;br /&gt;
* Sample Project c sources, include files, and make files for an example project&lt;br /&gt;
* UserManualTutorials c sources, include files, and make files for User Manual tutorials and application example &lt;br /&gt;
* Excel configuration file to help produce oceos_config.h can be downloaded from [[Media:OCEOS_Config.xlsx]] &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The source and build files associated with the example application referred to in this manual are located in the folder &amp;lt;installation-folder&amp;gt; \UserManualTutorials\asw.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''asw.h''' &amp;lt;blockquote&amp;gt;Simple application header.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''asw.c''' &amp;lt;blockquote&amp;gt;Simple application example. This file is a self-contained example of an OCEOS application including tasks, mutexes, semaphores, and dataqueues.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''oceos_config.h''' &amp;lt;blockquote&amp;gt;This is the OCEOS application header file where the developer specifies the number of tasks, mutexes, sempahores, dataqs, log entries, and readyq entries. These numbers are used to allocate the &lt;br /&gt;
memory required for storing oceos variables. The definitions to be specified follow.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_configuration2.jpg]]&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
Notes: &amp;lt;/br&amp;gt;&lt;br /&gt;
# The application must create the number of tasks, mutexes, semaphores or dataqs specified in this header, otherwise an error will be returned from oceos_init_finish().&lt;br /&gt;
# LOG_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# FIXED_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# DYN_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# Enumerated types are recommended for names of tasks, mutexes, semaphores and dataqs. This header file contains some examples.&lt;br /&gt;
&lt;br /&gt;
'''oceos_config.c''' &amp;lt;blockquote&amp;gt;This file contains the OCEOS data areas and the following functions:&lt;br /&gt;
# int application_init() This function initialises the oceos data area.&lt;br /&gt;
# void oceos_on_error(void* ptr) The developer should code this function to implement actions in case of a system error.&lt;br /&gt;
# void oceos_on_full_log(void* ptr)&lt;br /&gt;
The developer should code this function which is called when the system log is two-thirds full.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''makefile &amp;amp; makefile.mk''' &amp;lt;blockquote&amp;gt;These file are provided to facilitate building the asw application. Some local edits are required to point to the local compiler folders.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building the example application ===&lt;br /&gt;
&lt;br /&gt;
Download and install the BCC2 compiler [https://www.gaisler.com/index.php/downloads/compilers from here]. &lt;br /&gt;
&lt;br /&gt;
Use the Makefile provided or use the following commands to compile and link the application.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c asw.c -o asw.o&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c oceos_config.c -o oceos_config.o&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang asw.o oceos_config.o -o asw-gr716.elf -qbsp=gr716 -mcpu=leon3 -qsvt -qnano -Wall -LC:/projects/oce/oceos/trunk/oceos_product/oceoc/build/ -loceos -Wl,-Map=asw-gr716.map&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
# sparc-gaisler-elf-clang Ensure the path to the compiler has been configured. The llvm clang compiler is recommended as the OCEOS library was compiled with it.&lt;br /&gt;
# -I. -Iinclude -I&amp;lt;bcc-install-folder&amp;gt;/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include This -I option allows paths to include files to be passed to the compiler.&lt;br /&gt;
# -qbsp=gr716 This option specifies the compiler gr716 board support package.&lt;br /&gt;
# -mcpu=leon3 This option specifies the processor type.&lt;br /&gt;
# -Wall Display all warning messages.&lt;br /&gt;
# -c Compile only (linking not required).&lt;br /&gt;
# -o &amp;lt;filename&amp;gt; Specify the output filename.&lt;br /&gt;
# -qsvt Use the single-vector trap model described in “SPARC-V8 Supplement, SPARC-V8 Embedded (V8E) Architecture Specification”.&lt;br /&gt;
# -qnano Use a version of the newlib C library compiled for reduced foot print. The nano version implementations of the fprintf() fscanf() family of functions are not fully C standard compliant. Code size can decrease with up to # KiB when printf() is used.&lt;br /&gt;
# -L&amp;lt;path-to-oceos-library-file&amp;gt; Specify the path where liboceos.a is located.&lt;br /&gt;
# -loceos Instructs linker to use library liboceos.a&lt;br /&gt;
# -Wl,-Map=asw-gr716.map Instructs the linker to generate a map file with the name asw-gr716.map. This optional map file details the memory map of all functions and data.&lt;br /&gt;
# Consult the BCC manual for other options.&lt;br /&gt;
&lt;br /&gt;
The application executable (in this case asw.elf) can now be downloaded and executed on the target GR716 hardware. A debug tool such as DMON or GRMON is required for this. DMON provides specific support of OCEOS.&lt;br /&gt;
&lt;br /&gt;
'''''Important Note'''''&lt;br /&gt;
Up to BCC version 2.1.2 bcc_inline.h needs to be changed as it does not function on the GR716 as expected. The file is located in …\bcc-2.x.x-llvm\sparc-gaisler-elf\bsp\gr716\include\bcc\ for llvm and …\bcc-2.x.x-gcc\sparc-gaisler-elf\bsp\gr716\include\bcc for gcc.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* OCEOS comment out until BCC fix&lt;br /&gt;
 #ifdef __BCC_BSP_HAS_PWRPSR&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         uint32_t ret;&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
               &amp;quot;sll %4, %1, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;or %%o1, %2, %4\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;.word 0x83882000\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;rd %%psr, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;andn %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;wr %4, %%o2, %%psr\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;and %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;srl %%o2, %1, %0\n\t&amp;quot;&lt;br /&gt;
                 : &amp;quot;=r&amp;quot; (ret)&lt;br /&gt;
                 : &amp;quot;i&amp;quot; (PSR_PIL_BIT), &amp;quot;i&amp;quot; (PSR_ET), &amp;quot;i&amp;quot; (PSR_PIL), &amp;quot;r&amp;quot; &lt;br /&gt;
 (newpil)&lt;br /&gt;
                 : &amp;quot;o1&amp;quot;, &amp;quot;o2&amp;quot;&lt;br /&gt;
         );&lt;br /&gt;
         return ret;&lt;br /&gt;
 }&lt;br /&gt;
 #else &lt;br /&gt;
 */&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         register uint32_t _val __asm__(&amp;quot;o0&amp;quot;) = newpil;&lt;br /&gt;
         /* NOTE: nop for GRLIB-TN-0018 */&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
                 &amp;quot;ta %1\nnop\n&amp;quot; :&lt;br /&gt;
                 &amp;quot;=r&amp;quot; (_val) :&lt;br /&gt;
                 &amp;quot;i&amp;quot; (BCC_SW_TRAP_SET_PIL), &amp;quot;r&amp;quot; (_val)&lt;br /&gt;
         );&lt;br /&gt;
         return _val;&lt;br /&gt;
 } &lt;br /&gt;
 /* For OCEOS &lt;br /&gt;
 #endif&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If bcc_inline.h is not modified traps may be left disabled or in REX mode an illegal opcode trap is generated. [GRLIB]&lt;br /&gt;
&lt;br /&gt;
== Mode selection and control ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library with header files for applications wishing to use it. There are two primary modes of operation on the GR716 as follows:&lt;br /&gt;
* SPARC V8 32-bit Mode &amp;lt;/br&amp;gt; 32-bit mode is the standard instruction word size on the SPARC V8. An OCEOS object library is provided for 32-bit mode (gcc &amp;amp; llvm)&lt;br /&gt;
* REX 16-bit mode &amp;lt;/br&amp;gt; REX mode allows the GR716 to execute 16-bit instructions. Applications running in rex mode occupy a smaller memory footprint. The compiler option -mrex should be used and -Oz for the smallest footprint.&lt;br /&gt;
&lt;br /&gt;
It is an application design choice as to which mode is used.&lt;br /&gt;
&lt;br /&gt;
== Normal operations ==&lt;br /&gt;
&lt;br /&gt;
This section describes the OCEOS directives used to in most applications. See file asw.c for example.&lt;br /&gt;
&lt;br /&gt;
The calls to get OCEOS running are:&lt;br /&gt;
&lt;br /&gt;
# application_init – uses oceoc_init to Initialise fixed data and start system time and log&lt;br /&gt;
# oceos_task_create - Create task setting priority, no of jobs, ..etc.&lt;br /&gt;
# oceos_init_finish – Initilise dynamic data area&lt;br /&gt;
# oceos_start – Start the scheduler and pass control to first task&lt;br /&gt;
&lt;br /&gt;
After steps 1 to 4 above tasks implement application functionality. If mutexes, semaphores, dataqs and/or timed actions are required they also are created at step 2. &amp;lt;/br&amp;gt;&lt;br /&gt;
Note: it is mandatory to create the number of mutexes, semaphores, and dataqs declared otherwise oceos_init_finish() will return an error.&lt;br /&gt;
&lt;br /&gt;
=== application_init() ===&lt;br /&gt;
&lt;br /&gt;
[[File:application_init.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create (…) ===&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
oceos_task_create prepares a task for execution. In the case above the parameters are:&lt;br /&gt;
* t_setup is an integer setup in the enumerated type in oceos_config.h. t_setup is used to identify this task to OCEOS thereafter. &lt;br /&gt;
[[File:enum_task_name.jpg]]&lt;br /&gt;
* 3 is the priority allocated to this task. 1 is the highest and 254 the lowest priority&lt;br /&gt;
* 3 is the priority threshold. The scheduler will only allow tasks higher than this priority to pre-empt task t_setup.&lt;br /&gt;
* 1 is the maximum number of jobs for task t_setup. 15 is the maximum number of jobs that can be ready-to-run for any task.&lt;br /&gt;
* 0 indicating that floating point is not used by this task. Enabling floating point for a task causes the scheduler to store all floating point registers on the stack when the job is pre-empted. If the job is not using floating point this causes inefficiency.&lt;br /&gt;
* 1 causes the task to be enabled on when oceos is started.&lt;br /&gt;
* setup_start is the name of the function to be executed for this task. The code for setup_start is in asw.c and the function declared in asw.h.&lt;br /&gt;
[[File:setup_start.jpg]]&lt;br /&gt;
* setup_end is the function called when task t_setup terminates.&lt;br /&gt;
[[File:setup_end.jpg]]&lt;br /&gt;
* 0 instructs the scheduler that there is no maximum execution time for this task. If a value (in microseconds) is specified the scheduer will raise an error if the task exceeds this execution time.&lt;br /&gt;
* 0 instructs the scheduler that there is no minimum time between executions of this task. If a time in microseconds is specified the scheduler will raise an error if this value is violated.&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish() ===&lt;br /&gt;
This function must be called before OCEOS is started. It completes the initialisation of OCEOS data for the application.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_init_finish.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_start() ===&lt;br /&gt;
&lt;br /&gt;
This function starts task scheduling in OCEOS. It should never return from this function.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters passed to oceos_start are:&lt;br /&gt;
* fixed_data is a pointer to the start of the fixed data area. It is declared in oceos_config.c.&lt;br /&gt;
* t_setup is the ID of the task to be set executing when OCEOS starts (in oceos_config.h).&lt;br /&gt;
* Optional pointer that will be passed to the task started, here t_setup.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive starts an instance of a task, called a job in OCEOS. In this case start means puts an instance of the task, a job, on the ready-to-run queue, and performs a reschedule.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; If it is the highest priority job ready-to-run, it will be set running by the scheduler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The parameters passed to it are the task ID and a pointer. It returns an integer indicating the status of the call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many cases the first task to be run by OCEOS will perform application initialisation and then start the other application tasks including the idle task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex. It must be called before oceos_init_finish(). Parameters passed are the mutex ID and the priority ceiling for the mutex.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling is the priority of the highest task that uses the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note that the user must determine this priority ceiling as part of the application design. &lt;br /&gt;
OCEOS relies on the developer to specify the correct priority ceiling.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive assigns the mutex to the calling job. It should always be successful because a job should only be set running if the mutex is available to it.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_wait.jpg]]&lt;br /&gt;
&lt;br /&gt;
The mutex ID is the only parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive releases a mutex from a job. It will cause a reschedule and if a higher priority job has been waiting on the mutex it will start causing this job to be pre-empted.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The only parameter to the directive is the mutex ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a counting semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_create2.jpg |700px]]&lt;br /&gt;
&lt;br /&gt;
* Semaphore ID (0 to 62)&lt;br /&gt;
* Maximum No of permits (1 to 4094)&lt;br /&gt;
* Starting number of permits (1 to 4094)&lt;br /&gt;
* Maximum number of jobs on this semaphore queue (1 to 254)&lt;br /&gt;
* Whether timeout is used in oceos_sem_wait_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameter is:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted.&lt;br /&gt;
If a timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart_timeout.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer, long long)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive increments (signals) the specified semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_sem_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The semaphore ID is the sole parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a data queue with specified ID&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_create2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Data Queue Size (1 to 255)&lt;br /&gt;
* Data Queue maximum number of pending jobs (1 to 255)&lt;br /&gt;
* Data Queue roll-overs enable/disable (0 or 1)&lt;br /&gt;
* Whether timeout is used in oceos_dataq_read_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A timeout in microseconds can be set, after which the task will not be restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart_timeout2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive puts a pointer on the specified data queue.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_dataq_write.jpg]]&lt;br /&gt;
&lt;br /&gt;
Parameters are :&lt;br /&gt;
* Data queue ID (0 to 62)&lt;br /&gt;
* Pointer to be put on queue (void *ptr)&lt;br /&gt;
&lt;br /&gt;
== Normal termination ==&lt;br /&gt;
&lt;br /&gt;
It is not normal for OCEOS to terminate. Application tasks usually continue to execute without stopping. If all tasks terminate the system goes to sleep mode and only an interrupt can restart activity.&lt;br /&gt;
&lt;br /&gt;
== Error conditions ==&lt;br /&gt;
&lt;br /&gt;
Error conditions are handled in 4 different ways by OCEOS as follows:&lt;br /&gt;
* Directive return codes allowing application take appropriate action&lt;br /&gt;
* The System Log keeps a record of problems and when they occurred&lt;br /&gt;
* The System State variable indicates the current state of OCEOS&lt;br /&gt;
* The watchdog provides a fallback reset in unpredictable situations&lt;br /&gt;
&lt;br /&gt;
=== Directive return codes ===&lt;br /&gt;
&lt;br /&gt;
OCEOS is driven by directives described in the Reference section below. All directives return a status to be checked by the application. The directive return status is either success or a code indicating why it failed. The table below is taken from oceos.h. It is the responsibility of the application to take appropriate action if a directive call fails.&lt;br /&gt;
&lt;br /&gt;
[[File:Enum_directive_status2.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== The System Log ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;When a problem arises, either in application code or in OCEOS itself, it is useful to have a record of &amp;lt;/p&amp;gt;&lt;br /&gt;
# '''when''' it happened&lt;br /&gt;
# '''what''' kind of problem it was&lt;br /&gt;
# '''where''' it happened.&lt;br /&gt;
&amp;lt;p&amp;gt;The primary purpose of the System Log is to provide this ‘when’, ‘what’, and ‘where’ information.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It does so as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''when''':   the low 32-bits of the system time are automatically recorded when a log entry is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''what''':   an 8-bit number allows 256 different types of entry be specified. Half of these entry types (0x80 to 0xff) are reserved for internal us in OCEOS. The other 128 entry types (0 to 0x7f) are assigned their meanings by the application. (An OCEOS internal code reserved for that purpose is used if an application attempts to use an OCEOS internal code.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''where''':  a 24-bit number is included in each log entry. OCEOS itself uses this to indicate the OCEOS function where the log entry call was made and other information. Application code can use this number in whatever way is appropriate for the application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The log is located in the log area. This area starts at an address specified by the application developer, begins with a 32-bit constant sentinel value followed by a 32-bit count of the number of 32-bit words making up the area (including the sentinels) and ends with a 32-bit constant sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As frequent access to the log area is not likely to be needed the log area can be located in memory external to the GR716. The log area contents will then usually be preserved across system resets, and across system power on/off cycles if the external memory is non-volatile.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The log is structured as a circular buffer, with its read and write indices also stored in the log area. It is set up initially by oceos_init(). This does not overwrite the data currently in the log but resets the read and write indices to be equal and as far as can be determined after the most recent log entry. As the log indices are equal the log now appears empty when an attempt to read it in the usual way is made, but a special directive allows the application program read the data at any position in the log. Another directive allows the application reset all log entries.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Any system that uses OCEOS must have a system log. The number of entries in the log is specified in the system configuration structure, and must be within the specified range or 0, in which case a default value is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The header file oceos.h gives the structure of the log area and the values of the associated constants.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 struct log_entry{&lt;br /&gt;
  U32_t time32;&lt;br /&gt;
  unsigned int entry_type :8;&lt;br /&gt;
  unsigned int entry_comment :24;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
 * Log entry types used when creating a log entry (8 bits, from 0 to 255 only)&lt;br /&gt;
 */&lt;br /&gt;
 enum LOG_ENTRY_TYPE{&lt;br /&gt;
  LOG_SYS_OK = 0x80U,&lt;br /&gt;
  LOG_NULL_FATAL,&lt;br /&gt;
  LOG_OCEOS_ABORT,&lt;br /&gt;
  LOG_INVALID_SYSTEM_STATE,&lt;br /&gt;
  LOG_LOG_NOT_VALID_ENTRY,&lt;br /&gt;
  LOG_STATUS_INVALID,&lt;br /&gt;
  LOG_NULL_POINTER,&lt;br /&gt;
  LOG_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_FREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_UNFREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_RESET_FAIL,&lt;br /&gt;
  LOG_TIME_SCALER_FAIL,&lt;br /&gt;
  LOG_TIME_RELOAD_FAIL,&lt;br /&gt;
  LOG_TIME_COUNTER_FAIL,&lt;br /&gt;
  LOG_TIME_CONTROL_FAIL,&lt;br /&gt;
  LOG_TIME_POINTER_NULL,&lt;br /&gt;
  LOG_TIME_POINTER_LOW_NULL,&lt;br /&gt;
  LOG_TIME_START_FAIL,&lt;br /&gt;
  LOG_FIXED_INIT_FAIL,&lt;br /&gt;
  LOG_DYNAMIC_INIT_FAIL,&lt;br /&gt;
  LOG_INIT_TASK_START_FAIL,&lt;br /&gt;
  LOG_DEADLINE_MISSED,&lt;br /&gt;
  LOG_TASK_DISABLED,&lt;br /&gt;
  LOG_TASK_ENABLED,&lt;br /&gt;
  LOG_JOB_INVALID,&lt;br /&gt;
  LOG_JOB_NONE_FREE,&lt;br /&gt;
  LOG_JOB_NOT_EXECUTING,&lt;br /&gt;
  LOG_JOB_NOT_ACTIVE,&lt;br /&gt;
  LOG_READYQ_TOO_BIG,&lt;br /&gt;
  LOG_READYQ_SENTINEL_BAD,&lt;br /&gt;
  LOG_READYQ_FULL,&lt;br /&gt;
  LOG_READYQ_EMPTY,&lt;br /&gt;
  LOG_READYQ_PUT_DISABLED_TASK,&lt;br /&gt;
  LOG_READYQ_PUT_FAIL,&lt;br /&gt;
  LOG_READYQ_REMOVE_DONE,&lt;br /&gt;
  LOG_READYQ_REMOVE_FAIL,&lt;br /&gt;
  LOG_PARAM_BAD_ID,&lt;br /&gt;
  LOG_PARAM_BAD_TIME,&lt;br /&gt;
  LOG_PARAM_ACTION_MISSING,&lt;br /&gt;
  LOG_PARAM_JOB_MISSING,&lt;br /&gt;
  LOG_MUTEX_BAD_CEILING,&lt;br /&gt;
  LOG_MUTEX_ALREADY_HELD,&lt;br /&gt;
  LOG_MUTEX_ALREADY_FREE,&lt;br /&gt;
  LOG_MUTEX_WRONG_JOB,&lt;br /&gt;
  LOG_MUTEX_NESTING_BAD,&lt;br /&gt;
  LOG_MUTEX_EXIT_HOLDING,&lt;br /&gt;
  LOG_SEMAPHORE_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_SEMAPHORE_MAX_ALREADY_REACHED,&lt;br /&gt;
  LOG_SEMAPHORE_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_TIMED_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_TRANSFER_READYQ_FAIL,&lt;br /&gt;
  LOG_DATAQ_FULL,&lt;br /&gt;
  LOG_DATAQ_EMPTY,&lt;br /&gt;
  LOG_DATAQ_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_DATAQ_PENDING_QUEUE_FULL,&lt;br /&gt;
  LOG_DATAQ_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_DATAQ_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_DATAQ_TIMED_JOB_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_NULL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_STOP_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_NOT_INIT,&lt;br /&gt;
  LOG_TIMED_ACTION_INT_REG_FAILED,&lt;br /&gt;
  LOG_TIMED_ACTION_INVALID,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_INDEX,&lt;br /&gt;
  LOG_TIMED_ACTION_MISSED,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_FULL,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_EMPTY,&lt;br /&gt;
  LOG_TIMED_ACTION_PUT_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_JOB_ID,&lt;br /&gt;
  LOG_TIMED_ACTION_DO_FAIL,&lt;br /&gt;
  LOG_SYSTEM_ERROR,&lt;br /&gt;
  LOG_TIME_BSP_SYSFREQ_NULL,&lt;br /&gt;
  LOG_SEMAPHORE_TIMEOUT_NOT_INIT,  &lt;br /&gt;
  LOG_DATAQ_TIMEOUT_NOT_INIT, &lt;br /&gt;
  LOG_TIMED_ACTION_START_WHILE_RUNNING,&lt;br /&gt;
  LOG_INT_HANDLER_IS_NULL,&lt;br /&gt;
  LOG_SET_OCEOS_TRAP_HANDLER_FAILED,&lt;br /&gt;
  LOG_INT_CALLED_NO_INIT,&lt;br /&gt;
  LOG_FAILED_SET_INT_PRIO,  &lt;br /&gt;
  LOG_FAILED_PENDSV_INIT,&lt;br /&gt;
  LOG_SYS_TIME_NOT_INIT    &lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_add_entry(&lt;br /&gt;
 enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
 const unsigned int // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_remove_entry(struct log_entry * const);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_get_indexed_entry(&lt;br /&gt;
 const unsigned int,&lt;br /&gt;
 struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The System State variable ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/p&amp;gt;OCEOS maintains a system state variable which shows the current state of the system. States are shown below. If the system state deviates from normal (value 0) the user defined function oceos_on_error(..) is called by OCEOS. The source code for this function is located config.c and should be written by the application developer to take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directives oceos_system_state_get and oceos_system_state_set are provided to allow the application to access the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void oceos_on_error(void* ptr) { // Application dependent error handling code should be included here&lt;br /&gt;
 return;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
 * The 32-bit system state variable indicates the current system state&lt;br /&gt;
 */&lt;br /&gt;
 #define STATUS_NORMAL 0u // System State Normal&lt;br /&gt;
 #define STATUS_EDAC_INTERNAL 1u // Uncorrectable error in internal memory&lt;br /&gt;
 #define STATUS_EDAC_EXTERNAL 2u // Uncorrectable error in external memory&lt;br /&gt;
 #define STATUS_MEM_PROT_1 4u // Invalid access memory protection unit 1&lt;br /&gt;
 #define STATUS_MEM_PROT_2 8u // Invalid access memory protection unit 2&lt;br /&gt;
 #define STATUS_DISABLED_TASK_START 0x10u // An attempt to start a disabled task&lt;br /&gt;
 #define STATUS_TASK_JOB_LIMIT_OVER 0x20u // An attempt to execute a task when its jobs limit is already reached.&lt;br /&gt;
 #define STATUS_JOB_OVER_TIME 0x40u // Job time from creation to completion exceeds allowed maximum for a task.&lt;br /&gt;
 #define STATUS_JOB_INTERVAL_SHORT 0x80u // Minimum time between job creations is less than the allowed minimum for task&lt;br /&gt;
 #define STATUS_READYQ_FULL 0x100u // Ready queue unable to accept job as result of being full&lt;br /&gt;
 #define STATUS_MUTEX_ALREADY_HELD 0x200u // Mutex wait() when mutex already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_HELD 0x400u // Mutex signal() when not already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_RETURNED 0x800u // Mutex not returned before job terminates&lt;br /&gt;
 #define STATUS_SEMAPHORE_JOBS_FULL 0x1000u // Attempt to add job to semaphore pending list when list full&lt;br /&gt;
 #define STATUS_DATAQ_FULL 0x2000u // Data queue write when queue already full&lt;br /&gt;
 #define STATUS_DATAQ_JOBS_FULL 0x4000u // Attempt to add job to queue pending list when list full&lt;br /&gt;
 #define STATUS_TIMED_JOBS_FULL 0x8000u // Timed jobs queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_JOB_LATE 0x10000u // Timed jobs queue late job transfer to scheduler&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_FULL 0x20000u // Timed output queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_LATE 0x40000u // Timed output late&lt;br /&gt;
 #define STATUS_BAD_LOG 0x80000000u // System Log corruption&lt;br /&gt;
 #define STATUS_INVALID 0xffffffffu // Invalid system state&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The watchdog ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 provides watchdog functionality (ref: GR716 Advanced Data Sheet and User’s Manual). OCEOS provides functions to allow applications to use this watchdog functionality (see section 10 for more details). It is expected that OCEOS applications using the watchdog have a low priority task to continually reset the watchdog timer using the directive oceos_system_watchdog_reset(..). If the watchdog reaches its timeout value this is an indication that a severe error has occurred and a hardware reset is generated by the watchdog unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application when rebooted can optionally check the system log, and last system state to determine the cause of the watchdog reboot and take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hardware errors ===&lt;br /&gt;
&lt;br /&gt;
Hardware errors can come from a number of sources including the following:&lt;br /&gt;
* Uncorrectable memory errors&lt;br /&gt;
* Memory protection violations&lt;br /&gt;
* Brown-out or low power&lt;br /&gt;
The OCEOS philosophy to dealing with these and other hardware faults causing interrupts is to provide directives enabling the application to take appropriate actions. OCEOS directives available for application recovery are:&lt;br /&gt;
* oceos_interrupt_handle_register This directive may be used to setup application recovery interrupt service routines.&lt;br /&gt;
* oceos_exit This directive may be called to exit OCEOS back to the application for appropriate recovery actions.&lt;br /&gt;
* oceos_log_get_indexed_entry This directive may be used as part of the application fault analysis.&lt;br /&gt;
* oceos_system_state_get This action allows the application obtain the system status to determine appropriate recovery action.&lt;br /&gt;
&lt;br /&gt;
=== Overload and system failure ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overloads and system failure are different but have some common features. Both can lead to an unexpected system restart, and to the question ‘what caused that?’. Both can sometimes be anticipated if warning signs are noticed. It may even be possible to avoid them by taking appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Some thoughts and suggestions about them and OCEOS follow below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Overload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overload generally refers to insufficient CPU time to handle a situation.&lt;br /&gt;
Can also be a memory shortage, for example insufficient stack space.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;A task missing a soft deadline - needs to be noted&amp;lt;/li&amp;gt; &lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;A task missing a hard deadline - may be catastrophic&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Watchdog timeout - hardware reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inability to start a task due to memory shortage&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Interrupts more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task pre-empted more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Tasks start requests more frequent than expected&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inappropriate allocation of task priorities&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;One or more tasks using more than the expected CPU time (should not happen)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Holding one or more mutexes for too long&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Using mutexes in a non-nested manner&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Insufficient stack space&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;(With OCEOS unbounded priority inversion cannot occur.)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;(With OCEOS chained blocking cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;(With OCEOS deadlocks cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Information available for comparison to expected values to detect potential overload'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Task maximum duration – job creation time to termination time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task maximum CPU time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Task minimum time between start requests&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Task number of times pre-empted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Task maximum current jobs for a task&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Watchdog timer nearly timed out when reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Stack pointer approaching limit of allowed range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Et alia&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Disable certain interrupts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Disable a task or tasks&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Kill currently executing job&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== System failure ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;System failure generally refers to the CPU ceasing to execute instructions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Can also be a reference to the operating system (OCEOS) having to exit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Usually associated with hardware problems, but software can do it too.&amp;lt;/p&amp;gt;&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;OCEOS exit (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;CPU stops execution (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;A subsequent restart (hopefully)&amp;lt;/li&amp;gt;&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Critical OCEOS data corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Un-correctable memory error&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Memory hardware failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Power failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Environment more demanding than design anticipated causing hardware problems&amp;lt;/li&amp;gt;&lt;br /&gt;
''Warning signs that can indicate something wrong at system level'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Sentinels on OCEOS critical data areas corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Stack pointer approaching limit of range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Corrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Uncorrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Voltage levels - brown out detection interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Use EDAC scrubber units to continually regenerate all RAM&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Use MEMPROT unit to restrict OCEOS fixed data write access to the scrubber only&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Current System State ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Before discussing reports it seems appropriate to describe how the system state is stored and accessed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - OCEOS and the Application software'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For OCEOS this is given by its fixed data area, its dynamic data area, and its log data area. Also by some heap items and the stack and registers, including the PC. The latter are also relevant to the application state.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The locations and sizes of three OCEOS areas are determined by the application. Their lay-outs are known. A meta-data structure in the fixed area provides pointers to the principal fields within each data area and simplifies access by OCEOS and by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The three OCEOS areas are available for inspection after OCEOS exits and before it restarts as well as while it is running. This helps after a restart in assessing what went wrong, as well as allowing an application check for lurking problems while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(OCEOS does not allow tasks etc. be created once scheduling has begun, and as a result does not need to use dynamic memory allocation. The memory areas it uses can thus be fixed in advance, their locations and sizes determined by the application.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The task information items mentioned above are automatically updated by OCEOS in the dynamic data area and can be accessed by the application at any time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system state variable contains flags that indicate a certain problem has occurred. It is automatically updated by OCEOS using ‘OR’ to avoiding losing information, typically a user defined function is called to deal with the problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two sets of flags are kept as part of the system state variable. One accumulates indicators of all problems that have occurred, and typically is reset by the application only after a restart. The other indicates current problems, and typically is reset by the user defined problem handling function.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system log records when, what, and in some cases where something occurred. It is automatically written to by OCEOS in certain conditions and can also be read and written by the application. (Codes for what from 0x80 to 0xff are reserved for use by OCEOS, codes 0 to 0x7f are available for use by the application. At present only 24 bits are used to indicate where, this can be expanded to e.g. include the PC or stack pointer.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;At present the log area contains the system state variable as well as the system log. The system state variable could equally well be stored in the dynamic data area.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - Hardware'':&lt;br /&gt;
&lt;br /&gt;
Registers&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 has 504 32-bit IU registers, organized in 31 windows. In addition there are the usual processor registers PC, SP, Y, %psr, %wim and %tbr, and ancillary state registers %asr16, %asr17, %asr20, %asr22-23, %asr24-31. There are also 32 floating point registers, each 32-bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Other units with registers that have a key role in determining the current hardware state include the interrupt controller, the clock gating units, the EDAC and memory scrubber units, and the statistics unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;After a reset registers may have been automatically reset to some initial value and their previous content lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EDAC&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The internal data and instruction RAMs and the external RAM have individual EDAC and scrubber units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Normally the scrubber units will be configured to cycle through the memory, reading each location and writing it back if an error is detected, thus helping reduce the likelihood of a double bit error.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a double bit error is detected, the scrubber units can be configured to halt with the current address in a scrubber register and generate an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The two scrubbers for the internal memory each have a 4-bit counter (ECNT) for the number of single bit errors corrected. This can be reset by writing 0 to it. Correctable errors do not cause an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The external scrubber unit counts both correctable and un-correctable errors it has encountered, and allows thresholds be set for each of these so that an interrupt is generated if either threshold is exceeded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;EDAC errors give rise to an interrupt on interrupt line 63 which is mapped by default to interrupt 19. A handler for this interrupt needs to be put in place by the ASW as what should be done depends on the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;if set up appropriately the EDAC system can also be used to get an indication of background radiation levels by periodically checking the number of single bit errors that have been corrected in a given time period. Again should be done, if required, by the ASW.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reporting====&lt;br /&gt;
&lt;br /&gt;
Two main types of report&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current system state, including checking for potential problems&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;System state when a problem has occurred&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Non-fatal problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Reporting the Current System State''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As all OCEOS data is readily available, and the application itself is running in kernel/supervisor mode and is able to access all registers, there is no obvious help required from OCEOS to enable an application analyse the current state of the system whenever it wishes and report on this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A different question is what conditions OCEOS itself should monitor and bring to the attention of the application so that the application can take action and perhaps prevent the emergence of a problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The standard OCEOS mechanism for bringing an anomaly to the attention of the application is to call a user defined problem handling function after updating the system state variable and making a system log entry.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
The question then becomes in what circumstances OCEOS should do this.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS will always notify the application if it detects a problem such as a task using a mutex whose ceiling is lower than the task’s priority (an application configuration error), or a task exiting while holding a mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, a deadline for the task (number of microseconds after request to start by which it should have completed) can be specified. OCEOS can automatically notify the application if a task has missed its deadline. Or alternatively, if the time when a task completed was dangerously close to its deadline.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, an expected minimum time between task start requests can be specified. OCEOS can automatically notify the application if a start request occurs sooner than this, or alternatively if the time between start requests was too close to the expected value.??&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
OCEOS can check the state of the system when it does a context switch, or when any of its directives are used, or when it performs a timed action. (Unlike many operating systems OCEOS does not depend on a regular timer tick interrupt.)&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
''Reporting System State after a problem has occurred''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the problem is non-fatal, so that OCEOS can continue, when OCEOS detects the problem it will call the user defined problem handling function after updating the system state variable and system log.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU continues to function but OCEOS cannot continue, e.g. due to an OCEOS data area being corrupted by the application, OCEOS will exit. The application can consult the OCEOS data areas and various hardware registers to determine why OCEOS had to exit. It can then restart OCEOS.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU itself must shut down, and warning is given of this before it must happen by e.g. a brown-out detector, then two reports are involved&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a short death report for use before the CPU shuts down&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a long death report put together after the system restarts&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Usually generated in an interrupt handler (e.g. brown-out detected)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The type of problem is identified by the interrupt caused&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS does not seem to have any role in reading registers, whether in EDAC or scrubber units or elsewhere, simpler to just read them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Same applies to system time if needed, just requires a timer register read.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current task and job (equivalent of thread) can be stored by OCEOS in same area as OCEOS system state variable to make both readable as one block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Other items that might be stored in this block by OCEOS include&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;system priority ceiling (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;interrupt nesting level (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on ready queue (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;current number of mutexes held (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on counting semaphore pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on data queue pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of actions on timed actions queue (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The interrupt handler might also store items in the block, e.g.&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;PC when the interrupt was called&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Stack pointer&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;EDAC/scrubber registers&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS can keep the block up to date each time a new job begins executing (not done at present but no problem). But just what should the block include??&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The block data will be preserved across resets depending on the memory used. If this is non-volatile it will be preserved across power fail/restore cycles, and accessible in creating the long death report after restart.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Don’t think OCEOS has a role in relation to the line or function where the error happened (using GCC/LLVM predefined macros, such as __LINE__)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;What other OCEOS summary information if any should kept in the quick death report data block? (The detailed information on task times etc are accessible but probably too much for the short death report.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; The application chooses the memory to be used for the OCEOS dynamic area and for the OCEOS log area. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If both of these are non-volatile a very detailed description of the state of the system when the reset occurred is available to the application after the restart and can be used by it to generate a report before it restarts OCEOS (which will overwrite the dynamic area).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the short death report block is stored in one of these areas it will also be available.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the two areas are volatile the above will still be true but only for resets that did not involve power failure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the areas are in GR716 internal memory the GR716 boot sequence needs to be taken into account. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; After a reset it is likely that register contents, whether in the CPU or elsewhere, will not have been preserved. This is true a fortiori if the reset was caused by a power failure. Critical register information, such as the PC and stack pointer, will need to be captured in the quick death report data block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Changing the default trap handler====&lt;br /&gt;
&lt;br /&gt;
The default trap handler provided by BCC may be changed by modifying trap_table_svt_tables.S provided with BCC. The default BCC trap handler __bcc_trap_table_svt_bad should be replaced with the ASW trap handler or the OCEOS default trap handler (__oceos_default_trap_handler) provided in the example applications (shown below). The application should now be recompiled and linked with the new trap_table_svt_tables.S. When application starts, all trap handlers will be in memory ready for use by the application.&lt;br /&gt;
&lt;br /&gt;
 /** &lt;br /&gt;
 * OCEOS default trap handler. &lt;br /&gt;
 */ &lt;br /&gt;
 void __oceos_default_trap_handler () &lt;br /&gt;
 { &lt;br /&gt;
   U32_t tt; &lt;br /&gt;
   __asm__ volatile ( &amp;quot;mov %%tbr, %0&amp;quot; : &amp;quot;=&amp;amp;r&amp;quot; (tt));&lt;br /&gt;
   tt = (tt &amp;amp; 0xff0) &amp;gt;&amp;gt; 4; &lt;br /&gt;
   // Log ERROR and return &lt;br /&gt;
   oceos_log_add_entry(LOG_SYSTEM_ERROR, tt); &lt;br /&gt;
   // Update System Variable &lt;br /&gt;
   U32_t current_state = oceos_system_state_get(); &lt;br /&gt;
   current_state |= STATUS_SYSTEM_ERROR; &lt;br /&gt;
   oceos_system_state_set(current_state); &lt;br /&gt;
   __asm__ volatile (&amp;quot;restore&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;jmp %l2&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;rett %l2 + 0x4&amp;quot;); &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Context Switch Logging ==&lt;br /&gt;
&lt;br /&gt;
'''Basic approach:'''&lt;br /&gt;
&lt;br /&gt;
If enabled, each time a context switch or interrupt occurs four 32-bit words are added to the context switch log.&lt;br /&gt;
&lt;br /&gt;
The first of these describes the type of switch and also gives the current window pointer (CWP) and the low 8 bits of the high 32 bits of the 64-bit system time when the switch occurred.&lt;br /&gt;
The second gives the 32-bit system time in microseconds at which the switch occurred.&lt;br /&gt;
&lt;br /&gt;
The third gives the start delay if a task is being started, otherwise a signed int giving the remaining time until the deadline or INT_MAX if the task has no deadline, a negative value gives by how much the deadline has been missed.&lt;br /&gt;
The fourth gives the current system stack pointer. &lt;br /&gt;
&lt;br /&gt;
The user specifies the number of entries in the context switch log in the application configuration. This size is given as a number in the range 3 to 12, resulting in from 2^3 to 2^12 entries. If a size outside this range is specified no context switch log is present (no header and no entries).&lt;br /&gt;
&lt;br /&gt;
If valid the size is stored in sysMetaPtr-&amp;gt;CS_log_entries_base2. If invalid this holds 0, CS logging is off.&lt;br /&gt;
&lt;br /&gt;
'''CS Log Structure:'''&lt;br /&gt;
&lt;br /&gt;
CS Header followed by circular buffer, each buffer entry four 32-bit words.&lt;br /&gt;
&lt;br /&gt;
''Switch information (first word):''&lt;br /&gt;
&lt;br /&gt;
*8 bits high time bits (31 to 24)&lt;br /&gt;
*5 bits CWP  (23 to 19)							  	      &lt;br /&gt;
*1 bit (18) switch type,  0=&amp;gt; starting, 1 =&amp;gt; interrupt or ending 				      &lt;br /&gt;
*1 bit (17) ‘from’ ID type, 0=&amp;gt; from task, 1 =&amp;gt; from interrupt				      &lt;br /&gt;
*1 bit (16) ‘to’ ID type, 0 =&amp;gt; to task, 1 =&amp;gt; to interrupt					      &lt;br /&gt;
*8 bits (15 to 8) ID of task/interrupt from which switching				      &lt;br /&gt;
*8 bits (7 to 0) ID of task/interrupt to which switching&lt;br /&gt;
 &lt;br /&gt;
:TASK_ID_INVALID (0xff) is used to indicate switching to or from the scheduler itself. 	  The interrupt ID 0 is not expected to occur, used as TO when CPU put to sleep	     Initialised by oceos_start() to 0x0000ffff (invalid as scheduler doesn’t switch to itself).&lt;br /&gt;
&lt;br /&gt;
''Context switch time word (second word):''&lt;br /&gt;
&lt;br /&gt;
:Low 32 bits of the time at which switch happened. The next 8 bits of the 64-bit system time are given in the switch information word, giving an overall 40-bit time value. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''Start wait time / deadline time margin word (third word):''&lt;br /&gt;
&lt;br /&gt;
:When first starting a task, the delay between the start request and execution beginning. Otherwise a signed int giving remaining time until deadline or 0x7fffffff if no deadline. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''System stack pointer (fourth word):''&lt;br /&gt;
&lt;br /&gt;
:System stack pointer when switch was made. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
'''Storage:'''&lt;br /&gt;
&lt;br /&gt;
Stored in log area immediately after last system log entry and before END_SENTINEL for log area.&lt;br /&gt;
&lt;br /&gt;
Space needed for CS log is included in log area size recorded at the start of the log area.&lt;br /&gt;
&lt;br /&gt;
Number of CS log entries is 2^size unless size is invalid, in which case no storage is used.&lt;br /&gt;
&lt;br /&gt;
If sysMetaPtr-&amp;gt;CS_log_entries_base2 is outside the allowed range (typically 0) no context switch logging is done. The CS header is not present, END_SENTINEL is at that position instead.&lt;br /&gt;
&lt;br /&gt;
== Recover runs ==&lt;br /&gt;
&lt;br /&gt;
The previous section describes the error diagnostic facilities provided by OCEOS. The recovery procedure is the responsibility of the application. In the worst case a system reset can be initiated by the application. The table below shows some failure modes and recommended actions to recover.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;text-align:left;&amp;quot;| SFMEA ID&lt;br /&gt;
! Failure cause&lt;br /&gt;
! Recommended action&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0010&lt;br /&gt;
|ASW sets up a non-schedulable set of tasks&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0020&lt;br /&gt;
|ASW sets up a task that may demands excessive CPU or Memory resources&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom and map file to view memory usage&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0040&lt;br /&gt;
|Human error in OCEOS code&lt;br /&gt;
|Email details to support@ocetechnology.com&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0045&lt;br /&gt;
|Divide by zero occurs in OCEOS or in ASW.&lt;br /&gt;
|ASW to implement user defined trap&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0060&lt;br /&gt;
|Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW should use EDAC scrubber to correct error and report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0070&lt;br /&gt;
|Single Event Upset, permanent (burnt bit) in RAM&lt;br /&gt;
|ASW to refactor memory location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0080&lt;br /&gt;
|Single Event Upset, temporary in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to rewrite PROM location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0090&lt;br /&gt;
|Single Event Upset, permanent (burnt-proton impact etc) in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to set indicator to boot from backup image&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0100&lt;br /&gt;
|Double bit Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW to initiate warm or cold restart&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0110&lt;br /&gt;
|RAM memory corruption by any reason e.g. incorrect write address&lt;br /&gt;
|ASW dependent but warm or cold restart are options&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.16FM-0&lt;br /&gt;
|continuous false alarm&lt;br /&gt;
|ASW to reduce alarm check interval amd mark as ignore&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0130&lt;br /&gt;
|deadlock occurs&lt;br /&gt;
|Deadlock cannot occur from OCEOS directives&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0140&lt;br /&gt;
|clock corrupted, frozen or rate drifts (HSIA crystal failure)&lt;br /&gt;
|ASW to trigger watchfod restart and report issue&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0150&lt;br /&gt;
|output before required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0160&lt;br /&gt;
|output after required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=706</id>
		<title>OCEOS Operation</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=706"/>
		<updated>2021-10-01T12:33:02Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* The System Log */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Operations basics =&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library, header files(s), and application source files that can be compiled and linked with the standard BCC gcc or clang tools and libraries to provide a real-time multitasking application. OCEOS uses BCC library calls for some system functions. These functions are provided in the BCC board support package for the GR716. The minimum memory footprint for OCEOS is shown in the table below. Core modules occupy less than 10K bytes.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_size.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Operations manual =&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is structured as a set of managers each providing OCEOS service calls. &amp;lt;/br&amp;gt;&lt;br /&gt;
The activities supported by these managers are: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|''''' Initialization manager ''''':&lt;br /&gt;
|initializing the hardware and OCEOS itself&lt;br /&gt;
|-&lt;br /&gt;
|''''' Task manager ''''':&lt;br /&gt;
|handling tasks and jobs, including scheduling&lt;br /&gt;
|-&lt;br /&gt;
|''''' Interrupt manager ''''':&lt;br /&gt;
|setting up trap handlers&lt;br /&gt;
|-&lt;br /&gt;
|''''' Clock manager ''''':&lt;br /&gt;
|providing time of day, dates, and alarms&lt;br /&gt;
|-&lt;br /&gt;
|''''' Timer manager ''''':&lt;br /&gt;
|interval timing and alarms, timed outputs and jobs&lt;br /&gt;
|-&lt;br /&gt;
|''''' Mutex manager ''''':&lt;br /&gt;
|mutual exclusion management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Semaphore manager ''''':&lt;br /&gt;
|counting semaphore management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Data queue manager ''''':&lt;br /&gt;
|data queue management&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The directives provided by these managers are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== Set‐up and initialisation ==&lt;br /&gt;
&lt;br /&gt;
Setup for the use of OCEOS requires the user to prepare the development environment.&lt;br /&gt;
At a minimum this requires the installation for compilers, debug tool, editors, …etc.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
=== DMON OCEOS Support===&lt;br /&gt;
:OCE added OCEOS support to DMON to help user in debugging application software. Detailed manual and available functionality can be found [[DMON_OCEOS_Support|'''here''']].&lt;br /&gt;
&lt;br /&gt;
[[File:Cpu_load_main.png|600px|Cpu Load View]] [[File:Cpu_profile_main.png|600px|Cpu Profile View]]&lt;br /&gt;
&lt;br /&gt;
=== Files provided with OCEOS ===&lt;br /&gt;
&lt;br /&gt;
Unpack the OCEOS software into an appropriate folder on the computer. The folders are as follows:&lt;br /&gt;
&lt;br /&gt;
[[File:unzip_folders.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Documentation OCEOS User Manual and Quick Reference.&lt;br /&gt;
* include Include files required by the application&lt;br /&gt;
* OCEOS_GCC_LIB oceos.a object library for applications to be built with gcc&lt;br /&gt;
* OCEOS_LLNM_LIB oceos.a object library for applications to be built with llvm (32-bit)&lt;br /&gt;
* OCEOS_LLVM_REX_LIB oceos.a object library for applications to be built with llvm (16-bit REX mode)&lt;br /&gt;
* Sample Project c sources, include files, and make files for an example project&lt;br /&gt;
* UserManualTutorials c sources, include files, and make files for User Manual tutorials and application example &lt;br /&gt;
* Excel configuration file to help produce oceos_config.h can be downloaded from [[Media:OCEOS_Config.xlsx]] &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The source and build files associated with the example application referred to in this manual are located in the folder &amp;lt;installation-folder&amp;gt; \UserManualTutorials\asw.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''asw.h''' &amp;lt;blockquote&amp;gt;Simple application header.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''asw.c''' &amp;lt;blockquote&amp;gt;Simple application example. This file is a self-contained example of an OCEOS application including tasks, mutexes, semaphores, and dataqueues.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''oceos_config.h''' &amp;lt;blockquote&amp;gt;This is the OCEOS application header file where the developer specifies the number of tasks, mutexes, sempahores, dataqs, log entries, and readyq entries. These numbers are used to allocate the &lt;br /&gt;
memory required for storing oceos variables. The definitions to be specified follow.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_configuration2.jpg]]&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
Notes: &amp;lt;/br&amp;gt;&lt;br /&gt;
# The application must create the number of tasks, mutexes, semaphores or dataqs specified in this header, otherwise an error will be returned from oceos_init_finish().&lt;br /&gt;
# LOG_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# FIXED_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# DYN_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# Enumerated types are recommended for names of tasks, mutexes, semaphores and dataqs. This header file contains some examples.&lt;br /&gt;
&lt;br /&gt;
'''oceos_config.c''' &amp;lt;blockquote&amp;gt;This file contains the OCEOS data areas and the following functions:&lt;br /&gt;
# int application_init() This function initialises the oceos data area.&lt;br /&gt;
# void oceos_on_error(void* ptr) The developer should code this function to implement actions in case of a system error.&lt;br /&gt;
# void oceos_on_full_log(void* ptr)&lt;br /&gt;
The developer should code this function which is called when the system log is two-thirds full.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''makefile &amp;amp; makefile.mk''' &amp;lt;blockquote&amp;gt;These file are provided to facilitate building the asw application. Some local edits are required to point to the local compiler folders.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building the example application ===&lt;br /&gt;
&lt;br /&gt;
Download and install the BCC2 compiler [https://www.gaisler.com/index.php/downloads/compilers from here]. &lt;br /&gt;
&lt;br /&gt;
Use the Makefile provided or use the following commands to compile and link the application.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c asw.c -o asw.o&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c oceos_config.c -o oceos_config.o&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang asw.o oceos_config.o -o asw-gr716.elf -qbsp=gr716 -mcpu=leon3 -qsvt -qnano -Wall -LC:/projects/oce/oceos/trunk/oceos_product/oceoc/build/ -loceos -Wl,-Map=asw-gr716.map&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
# sparc-gaisler-elf-clang Ensure the path to the compiler has been configured. The llvm clang compiler is recommended as the OCEOS library was compiled with it.&lt;br /&gt;
# -I. -Iinclude -I&amp;lt;bcc-install-folder&amp;gt;/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include This -I option allows paths to include files to be passed to the compiler.&lt;br /&gt;
# -qbsp=gr716 This option specifies the compiler gr716 board support package.&lt;br /&gt;
# -mcpu=leon3 This option specifies the processor type.&lt;br /&gt;
# -Wall Display all warning messages.&lt;br /&gt;
# -c Compile only (linking not required).&lt;br /&gt;
# -o &amp;lt;filename&amp;gt; Specify the output filename.&lt;br /&gt;
# -qsvt Use the single-vector trap model described in “SPARC-V8 Supplement, SPARC-V8 Embedded (V8E) Architecture Specification”.&lt;br /&gt;
# -qnano Use a version of the newlib C library compiled for reduced foot print. The nano version implementations of the fprintf() fscanf() family of functions are not fully C standard compliant. Code size can decrease with up to # KiB when printf() is used.&lt;br /&gt;
# -L&amp;lt;path-to-oceos-library-file&amp;gt; Specify the path where liboceos.a is located.&lt;br /&gt;
# -loceos Instructs linker to use library liboceos.a&lt;br /&gt;
# -Wl,-Map=asw-gr716.map Instructs the linker to generate a map file with the name asw-gr716.map. This optional map file details the memory map of all functions and data.&lt;br /&gt;
# Consult the BCC manual for other options.&lt;br /&gt;
&lt;br /&gt;
The application executable (in this case asw.elf) can now be downloaded and executed on the target GR716 hardware. A debug tool such as DMON or GRMON is required for this. DMON provides specific support of OCEOS.&lt;br /&gt;
&lt;br /&gt;
'''''Important Note'''''&lt;br /&gt;
Up to BCC version 2.1.2 bcc_inline.h needs to be changed as it does not function on the GR716 as expected. The file is located in …\bcc-2.x.x-llvm\sparc-gaisler-elf\bsp\gr716\include\bcc\ for llvm and …\bcc-2.x.x-gcc\sparc-gaisler-elf\bsp\gr716\include\bcc for gcc.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* OCEOS comment out until BCC fix&lt;br /&gt;
 #ifdef __BCC_BSP_HAS_PWRPSR&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         uint32_t ret;&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
               &amp;quot;sll %4, %1, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;or %%o1, %2, %4\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;.word 0x83882000\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;rd %%psr, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;andn %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;wr %4, %%o2, %%psr\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;and %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;srl %%o2, %1, %0\n\t&amp;quot;&lt;br /&gt;
                 : &amp;quot;=r&amp;quot; (ret)&lt;br /&gt;
                 : &amp;quot;i&amp;quot; (PSR_PIL_BIT), &amp;quot;i&amp;quot; (PSR_ET), &amp;quot;i&amp;quot; (PSR_PIL), &amp;quot;r&amp;quot; &lt;br /&gt;
 (newpil)&lt;br /&gt;
                 : &amp;quot;o1&amp;quot;, &amp;quot;o2&amp;quot;&lt;br /&gt;
         );&lt;br /&gt;
         return ret;&lt;br /&gt;
 }&lt;br /&gt;
 #else &lt;br /&gt;
 */&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         register uint32_t _val __asm__(&amp;quot;o0&amp;quot;) = newpil;&lt;br /&gt;
         /* NOTE: nop for GRLIB-TN-0018 */&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
                 &amp;quot;ta %1\nnop\n&amp;quot; :&lt;br /&gt;
                 &amp;quot;=r&amp;quot; (_val) :&lt;br /&gt;
                 &amp;quot;i&amp;quot; (BCC_SW_TRAP_SET_PIL), &amp;quot;r&amp;quot; (_val)&lt;br /&gt;
         );&lt;br /&gt;
         return _val;&lt;br /&gt;
 } &lt;br /&gt;
 /* For OCEOS &lt;br /&gt;
 #endif&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If bcc_inline.h is not modified traps may be left disabled or in REX mode an illegal opcode trap is generated. [GRLIB]&lt;br /&gt;
&lt;br /&gt;
== Mode selection and control ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library with header files for applications wishing to use it. There are two primary modes of operation on the GR716 as follows:&lt;br /&gt;
* SPARC V8 32-bit Mode &amp;lt;/br&amp;gt; 32-bit mode is the standard instruction word size on the SPARC V8. An OCEOS object library is provided for 32-bit mode (gcc &amp;amp; llvm)&lt;br /&gt;
* REX 16-bit mode &amp;lt;/br&amp;gt; REX mode allows the GR716 to execute 16-bit instructions. Applications running in rex mode occupy a smaller memory footprint. The compiler option -mrex should be used and -Oz for the smallest footprint.&lt;br /&gt;
&lt;br /&gt;
It is an application design choice as to which mode is used.&lt;br /&gt;
&lt;br /&gt;
== Normal operations ==&lt;br /&gt;
&lt;br /&gt;
This section describes the OCEOS directives used to in most applications. See file asw.c for example.&lt;br /&gt;
&lt;br /&gt;
The calls to get OCEOS running are:&lt;br /&gt;
&lt;br /&gt;
# application_init – uses oceoc_init to Initialise fixed data and start system time and log&lt;br /&gt;
# oceos_task_create - Create task setting priority, no of jobs, ..etc.&lt;br /&gt;
# oceos_init_finish – Initilise dynamic data area&lt;br /&gt;
# oceos_start – Start the scheduler and pass control to first task&lt;br /&gt;
&lt;br /&gt;
After steps 1 to 4 above tasks implement application functionality. If mutexes, semaphores, dataqs and/or timed actions are required they also are created at step 2. &amp;lt;/br&amp;gt;&lt;br /&gt;
Note: it is mandatory to create the number of mutexes, semaphores, and dataqs declared otherwise oceos_init_finish() will return an error.&lt;br /&gt;
&lt;br /&gt;
=== application_init() ===&lt;br /&gt;
&lt;br /&gt;
[[File:application_init.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create (…) ===&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
oceos_task_create prepares a task for execution. In the case above the parameters are:&lt;br /&gt;
* t_setup is an integer setup in the enumerated type in oceos_config.h. t_setup is used to identify this task to OCEOS thereafter. &lt;br /&gt;
[[File:enum_task_name.jpg]]&lt;br /&gt;
* 3 is the priority allocated to this task. 1 is the highest and 254 the lowest priority&lt;br /&gt;
* 3 is the priority threshold. The scheduler will only allow tasks higher than this priority to pre-empt task t_setup.&lt;br /&gt;
* 1 is the maximum number of jobs for task t_setup. 15 is the maximum number of jobs that can be ready-to-run for any task.&lt;br /&gt;
* 0 indicating that floating point is not used by this task. Enabling floating point for a task causes the scheduler to store all floating point registers on the stack when the job is pre-empted. If the job is not using floating point this causes inefficiency.&lt;br /&gt;
* 1 causes the task to be enabled on when oceos is started.&lt;br /&gt;
* setup_start is the name of the function to be executed for this task. The code for setup_start is in asw.c and the function declared in asw.h.&lt;br /&gt;
[[File:setup_start.jpg]]&lt;br /&gt;
* setup_end is the function called when task t_setup terminates.&lt;br /&gt;
[[File:setup_end.jpg]]&lt;br /&gt;
* 0 instructs the scheduler that there is no maximum execution time for this task. If a value (in microseconds) is specified the scheduer will raise an error if the task exceeds this execution time.&lt;br /&gt;
* 0 instructs the scheduler that there is no minimum time between executions of this task. If a time in microseconds is specified the scheduler will raise an error if this value is violated.&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish() ===&lt;br /&gt;
This function must be called before OCEOS is started. It completes the initialisation of OCEOS data for the application.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_init_finish.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_start() ===&lt;br /&gt;
&lt;br /&gt;
This function starts task scheduling in OCEOS. It should never return from this function.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters passed to oceos_start are:&lt;br /&gt;
* fixed_data is a pointer to the start of the fixed data area. It is declared in oceos_config.c.&lt;br /&gt;
* t_setup is the ID of the task to be set executing when OCEOS starts (in oceos_config.h).&lt;br /&gt;
* Optional pointer that will be passed to the task started, here t_setup.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive starts an instance of a task, called a job in OCEOS. In this case start means puts an instance of the task, a job, on the ready-to-run queue, and performs a reschedule.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; If it is the highest priority job ready-to-run, it will be set running by the scheduler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The parameters passed to it are the task ID and a pointer. It returns an integer indicating the status of the call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many cases the first task to be run by OCEOS will perform application initialisation and then start the other application tasks including the idle task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex. It must be called before oceos_init_finish(). Parameters passed are the mutex ID and the priority ceiling for the mutex.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling is the priority of the highest task that uses the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note that the user must determine this priority ceiling as part of the application design. &lt;br /&gt;
OCEOS relies on the developer to specify the correct priority ceiling.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive assigns the mutex to the calling job. It should always be successful because a job should only be set running if the mutex is available to it.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_wait.jpg]]&lt;br /&gt;
&lt;br /&gt;
The mutex ID is the only parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive releases a mutex from a job. It will cause a reschedule and if a higher priority job has been waiting on the mutex it will start causing this job to be pre-empted.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The only parameter to the directive is the mutex ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a counting semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_create2.jpg |700px]]&lt;br /&gt;
&lt;br /&gt;
* Semaphore ID (0 to 62)&lt;br /&gt;
* Maximum No of permits (1 to 4094)&lt;br /&gt;
* Starting number of permits (1 to 4094)&lt;br /&gt;
* Maximum number of jobs on this semaphore queue (1 to 254)&lt;br /&gt;
* Whether timeout is used in oceos_sem_wait_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameter is:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted.&lt;br /&gt;
If a timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart_timeout.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer, long long)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive increments (signals) the specified semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_sem_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The semaphore ID is the sole parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a data queue with specified ID&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_create2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Data Queue Size (1 to 255)&lt;br /&gt;
* Data Queue maximum number of pending jobs (1 to 255)&lt;br /&gt;
* Data Queue roll-overs enable/disable (0 or 1)&lt;br /&gt;
* Whether timeout is used in oceos_dataq_read_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A timeout in microseconds can be set, after which the task will not be restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart_timeout2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive puts a pointer on the specified data queue.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_dataq_write.jpg]]&lt;br /&gt;
&lt;br /&gt;
Parameters are :&lt;br /&gt;
* Data queue ID (0 to 62)&lt;br /&gt;
* Pointer to be put on queue (void *ptr)&lt;br /&gt;
&lt;br /&gt;
== Normal termination ==&lt;br /&gt;
&lt;br /&gt;
It is not normal for OCEOS to terminate. Application tasks usually continue to execute without stopping. If all tasks terminate the system goes to sleep mode and only an interrupt can restart activity.&lt;br /&gt;
&lt;br /&gt;
== Error conditions ==&lt;br /&gt;
&lt;br /&gt;
Error conditions are handled in 4 different ways by OCEOS as follows:&lt;br /&gt;
* Directive return codes allowing application take appropriate action&lt;br /&gt;
* The System Log keeps a record of problems and when they occurred&lt;br /&gt;
* The System State variable indicates the current state of OCEOS&lt;br /&gt;
* The watchdog provides a fallback reset in unpredictable situations&lt;br /&gt;
&lt;br /&gt;
=== Directive return codes ===&lt;br /&gt;
&lt;br /&gt;
OCEOS is driven by directives described in the Reference section below. All directives return a status to be checked by the application. The directive return status is either success or a code indicating why it failed. The table below is taken from oceos.h. It is the responsibility of the application to take appropriate action if a directive call fails.&lt;br /&gt;
&lt;br /&gt;
[[File:Enum_directive_status2.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== The System Log ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;When a problem arises, either in application code or in OCEOS itself, it is useful to have a record of &amp;lt;/p&amp;gt;&lt;br /&gt;
# '''when''' it happened&lt;br /&gt;
# '''what''' kind of problem it was&lt;br /&gt;
# '''where''' it happened.&lt;br /&gt;
&amp;lt;p&amp;gt;The primary purpose of the System Log is to provide this ‘when’, ‘what’, and ‘where’ information.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It does so as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''when''':   the low 32-bits of the system time are automatically recorded when a log entry is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''what''':   an 8-bit number allows 256 different types of entry be specified. Half of these entry types (0x80 to 0xff) are reserved for internal us in OCEOS. The other 128 entry types (0 to 0x7f) are assigned their meanings by the application. (An OCEOS internal code reserved for that purpose is used if an application attempts to use an OCEOS internal code.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''where''':  a 24-bit number is included in each log entry. OCEOS itself uses this to indicate the OCEOS function where the log entry call was made and other information. Application code can use this number in whatever way is appropriate for the application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The log is located in the log area. This area starts at an address specified by the application developer, begins with a 32-bit constant sentinel value followed by a 32-bit count of the number of 32-bit words making up the area (including the sentinels) and ends with a 32-bit constant sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As frequent access to the log area is not likely to be needed the log area can be located in memory external to the GR716. The log area contents will then usually be preserved across system resets, and across system power on/off cycles if the external memory is non-volatile.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The log is structured as a circular buffer, with its read and write indices also stored in the log area. It is set up initially by oceos_init(). This does not overwrite the data currently in the log but resets the read and write indices to be equal and as far as can be determined after the most recent log entry. As the log indices are equal the log now appears empty when an attempt to read it in the usual way is made, but a special directive allows the application program read the data at any position in the log. Another directive allows the application reset all log entries.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Any system that uses OCEOS must have a system log. The number of entries in the log is specified in the system configuration structure, and must be within the specified range or 0, in which case a default value is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The header file oceos.h gives the structure of the log area and the values of the associated constants.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 struct log_entry{&lt;br /&gt;
  U32_t time32;&lt;br /&gt;
  unsigned int entry_type :8;&lt;br /&gt;
  unsigned int entry_comment :24;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
 * Log entry types used when creating a log entry (8 bits, from 0 to 255 only)&lt;br /&gt;
 */&lt;br /&gt;
 enum LOG_ENTRY_TYPE{&lt;br /&gt;
  LOG_SYS_OK = 0x80U,&lt;br /&gt;
  LOG_NULL_FATAL,&lt;br /&gt;
  LOG_OCEOS_ABORT,&lt;br /&gt;
  LOG_INVALID_SYSTEM_STATE,&lt;br /&gt;
  LOG_LOG_NOT_VALID_ENTRY,&lt;br /&gt;
  LOG_STATUS_INVALID,&lt;br /&gt;
  LOG_NULL_POINTER,&lt;br /&gt;
  LOG_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_FREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_UNFREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_RESET_FAIL,&lt;br /&gt;
  LOG_TIME_SCALER_FAIL,&lt;br /&gt;
  LOG_TIME_RELOAD_FAIL,&lt;br /&gt;
  LOG_TIME_COUNTER_FAIL,&lt;br /&gt;
  LOG_TIME_CONTROL_FAIL,&lt;br /&gt;
  LOG_TIME_POINTER_NULL,&lt;br /&gt;
  LOG_TIME_POINTER_LOW_NULL,&lt;br /&gt;
  LOG_TIME_START_FAIL,&lt;br /&gt;
  LOG_FIXED_INIT_FAIL,&lt;br /&gt;
  LOG_DYNAMIC_INIT_FAIL,&lt;br /&gt;
  LOG_INIT_TASK_START_FAIL,&lt;br /&gt;
  LOG_DEADLINE_MISSED,&lt;br /&gt;
  LOG_TASK_DISABLED,&lt;br /&gt;
  LOG_TASK_ENABLED,&lt;br /&gt;
  LOG_JOB_INVALID,&lt;br /&gt;
  LOG_JOB_NONE_FREE,&lt;br /&gt;
  LOG_JOB_NOT_EXECUTING,&lt;br /&gt;
  LOG_JOB_NOT_ACTIVE,&lt;br /&gt;
  LOG_READYQ_TOO_BIG,&lt;br /&gt;
  LOG_READYQ_SENTINEL_BAD,&lt;br /&gt;
  LOG_READYQ_FULL,&lt;br /&gt;
  LOG_READYQ_EMPTY,&lt;br /&gt;
  LOG_READYQ_PUT_DISABLED_TASK,&lt;br /&gt;
  LOG_READYQ_PUT_FAIL,&lt;br /&gt;
  LOG_READYQ_REMOVE_DONE,&lt;br /&gt;
  LOG_READYQ_REMOVE_FAIL,&lt;br /&gt;
  LOG_PARAM_BAD_ID,&lt;br /&gt;
  LOG_PARAM_BAD_TIME,&lt;br /&gt;
  LOG_PARAM_ACTION_MISSING,&lt;br /&gt;
  LOG_PARAM_JOB_MISSING,&lt;br /&gt;
  LOG_MUTEX_BAD_CEILING,&lt;br /&gt;
  LOG_MUTEX_ALREADY_HELD,&lt;br /&gt;
  LOG_MUTEX_ALREADY_FREE,&lt;br /&gt;
  LOG_MUTEX_WRONG_JOB,&lt;br /&gt;
  LOG_MUTEX_NESTING_BAD,&lt;br /&gt;
  LOG_MUTEX_EXIT_HOLDING,&lt;br /&gt;
  LOG_SEMAPHORE_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_SEMAPHORE_MAX_ALREADY_REACHED,&lt;br /&gt;
  LOG_SEMAPHORE_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_TIMED_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_TRANSFER_READYQ_FAIL,&lt;br /&gt;
  LOG_DATAQ_FULL,&lt;br /&gt;
  LOG_DATAQ_EMPTY,&lt;br /&gt;
  LOG_DATAQ_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_DATAQ_PENDING_QUEUE_FULL,&lt;br /&gt;
  LOG_DATAQ_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_DATAQ_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_DATAQ_TIMED_JOB_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_NULL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_STOP_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_NOT_INIT,&lt;br /&gt;
  LOG_TIMED_ACTION_INT_REG_FAILED,&lt;br /&gt;
  LOG_TIMED_ACTION_INVALID,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_INDEX,&lt;br /&gt;
  LOG_TIMED_ACTION_MISSED,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_FULL,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_EMPTY,&lt;br /&gt;
  LOG_TIMED_ACTION_PUT_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_JOB_ID,&lt;br /&gt;
  LOG_TIMED_ACTION_DO_FAIL,&lt;br /&gt;
  LOG_SYSTEM_ERROR,&lt;br /&gt;
  LOG_TIME_BSP_SYSFREQ_NULL,&lt;br /&gt;
  LOG_SEMAPHORE_TIMEOUT_NOT_INIT,  &lt;br /&gt;
  LOG_DATAQ_TIMEOUT_NOT_INIT, &lt;br /&gt;
  LOG_TIMED_ACTION_START_WHILE_RUNNING,&lt;br /&gt;
  LOG_INT_HANDLER_IS_NULL,&lt;br /&gt;
  LOG_SET_OCEOS_TRAP_HANDLER_FAILED,&lt;br /&gt;
  LOG_INT_CALLED_NO_INIT,&lt;br /&gt;
  LOG_FAILED_SET_INT_PRIO,  &lt;br /&gt;
  LOG_FAILED_PENDSV_INIT,&lt;br /&gt;
  LOG_SYS_TIME_NOT_INIT    &lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_add_entry(&lt;br /&gt;
 enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
 const unsigned int // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_remove_entry(struct log_entry * const);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_get_indexed_entry(&lt;br /&gt;
 const unsigned int,&lt;br /&gt;
 struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The System State variable ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/p&amp;gt;OCEOS maintains a system state variable which shows the current state of the system. States are shown below. If the system state deviates from normal (value 0) the user defined function oceos_on_error(..) is called by OCEOS. The source code for this function is located config.c and should be written by the application developer to take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directives oceos_system_state_get and oceos_system_state_set are provided to allow the application to access the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 void oceos_on_error(void* ptr) { // Application dependent error handling code should be included here&lt;br /&gt;
 return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
 * The 32-bit system state variable indicates the current system state&lt;br /&gt;
 */&lt;br /&gt;
 #define STATUS_NORMAL 0u // System State Normal&lt;br /&gt;
 #define STATUS_EDAC_INTERNAL 1u // Uncorrectable error in internal memory&lt;br /&gt;
 #define STATUS_EDAC_EXTERNAL 2u // Uncorrectable error in external memory&lt;br /&gt;
 #define STATUS_MEM_PROT_1 4u // Invalid access memory protection unit 1&lt;br /&gt;
 #define STATUS_MEM_PROT_2 8u // Invalid access memory protection unit 2&lt;br /&gt;
 #define STATUS_DISABLED_TASK_START 0x10u // An attempt to start a disabled task&lt;br /&gt;
 #define STATUS_TASK_JOB_LIMIT_OVER 0x20u // An attempt to execute a task when its jobs limit is already reached.&lt;br /&gt;
 #define STATUS_JOB_OVER_TIME 0x40u // Job time from creation to completion exceeds allowed maximum for a task.&lt;br /&gt;
 #define STATUS_JOB_INTERVAL_SHORT 0x80u // Minimum time between job creations is less than the allowed minimum for task&lt;br /&gt;
 #define STATUS_READYQ_FULL 0x100u // Ready queue unable to accept job as result of being full&lt;br /&gt;
 #define STATUS_MUTEX_ALREADY_HELD 0x200u // Mutex wait() when mutex already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_HELD 0x400u // Mutex signal() when not already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_RETURNED 0x800u // Mutex not returned before job terminates&lt;br /&gt;
 #define STATUS_SEMAPHORE_JOBS_FULL 0x1000u // Attempt to add job to semaphore pending list when list full&lt;br /&gt;
 #define STATUS_DATAQ_FULL 0x2000u // Data queue write when queue already full&lt;br /&gt;
 #define STATUS_DATAQ_JOBS_FULL 0x4000u // Attempt to add job to queue pending list when list full&lt;br /&gt;
 #define STATUS_TIMED_JOBS_FULL 0x8000u // Timed jobs queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_JOB_LATE 0x10000u // Timed jobs queue late job transfer to scheduler&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_FULL 0x20000u // Timed output queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_LATE 0x40000u // Timed output late&lt;br /&gt;
 #define STATUS_BAD_LOG 0x80000000u // System Log corruption&lt;br /&gt;
 #define STATUS_INVALID 0xffffffffu // Invalid system state&lt;br /&gt;
&lt;br /&gt;
=== The watchdog ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 provides watchdog functionality (ref: GR716 Advanced Data Sheet and User’s Manual). OCEOS provides functions to allow applications to use this watchdog functionality (see section 10 for more details). It is expected that OCEOS applications using the watchdog have a low priority task to continually reset the watchdog timer using the directive oceos_system_watchdog_reset(..). If the watchdog reaches its timeout value this is an indication that a severe error has occurred and a hardware reset is generated by the watchdog unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application when rebooted can optionally check the system log, and last system state to determine the cause of the watchdog reboot and take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hardware errors ===&lt;br /&gt;
&lt;br /&gt;
Hardware errors can come from a number of sources including the following:&lt;br /&gt;
* Uncorrectable memory errors&lt;br /&gt;
* Memory protection violations&lt;br /&gt;
* Brown-out or low power&lt;br /&gt;
The OCEOS philosophy to dealing with these and other hardware faults causing interrupts is to provide directives enabling the application to take appropriate actions. OCEOS directives available for application recovery are:&lt;br /&gt;
* oceos_interrupt_handle_register This directive may be used to setup application recovery interrupt service routines.&lt;br /&gt;
* oceos_exit This directive may be called to exit OCEOS back to the application for appropriate recovery actions.&lt;br /&gt;
* oceos_log_get_indexed_entry This directive may be used as part of the application fault analysis.&lt;br /&gt;
* oceos_system_state_get This action allows the application obtain the system status to determine appropriate recovery action.&lt;br /&gt;
&lt;br /&gt;
=== Overload and system failure ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overloads and system failure are different but have some common features. Both can lead to an unexpected system restart, and to the question ‘what caused that?’. Both can sometimes be anticipated if warning signs are noticed. It may even be possible to avoid them by taking appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Some thoughts and suggestions about them and OCEOS follow below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Overload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overload generally refers to insufficient CPU time to handle a situation.&lt;br /&gt;
Can also be a memory shortage, for example insufficient stack space.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;A task missing a soft deadline - needs to be noted&amp;lt;/li&amp;gt; &lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;A task missing a hard deadline - may be catastrophic&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Watchdog timeout - hardware reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inability to start a task due to memory shortage&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Interrupts more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task pre-empted more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Tasks start requests more frequent than expected&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inappropriate allocation of task priorities&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;One or more tasks using more than the expected CPU time (should not happen)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Holding one or more mutexes for too long&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Using mutexes in a non-nested manner&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Insufficient stack space&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;(With OCEOS unbounded priority inversion cannot occur.)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;(With OCEOS chained blocking cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;(With OCEOS deadlocks cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Information available for comparison to expected values to detect potential overload'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Task maximum duration – job creation time to termination time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task maximum CPU time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Task minimum time between start requests&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Task number of times pre-empted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Task maximum current jobs for a task&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Watchdog timer nearly timed out when reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Stack pointer approaching limit of allowed range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Et alia&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Disable certain interrupts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Disable a task or tasks&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Kill currently executing job&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== System failure ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;System failure generally refers to the CPU ceasing to execute instructions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Can also be a reference to the operating system (OCEOS) having to exit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Usually associated with hardware problems, but software can do it too.&amp;lt;/p&amp;gt;&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;OCEOS exit (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;CPU stops execution (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;A subsequent restart (hopefully)&amp;lt;/li&amp;gt;&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Critical OCEOS data corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Un-correctable memory error&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Memory hardware failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Power failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Environment more demanding than design anticipated causing hardware problems&amp;lt;/li&amp;gt;&lt;br /&gt;
''Warning signs that can indicate something wrong at system level'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Sentinels on OCEOS critical data areas corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Stack pointer approaching limit of range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Corrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Uncorrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Voltage levels - brown out detection interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Use EDAC scrubber units to continually regenerate all RAM&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Use MEMPROT unit to restrict OCEOS fixed data write access to the scrubber only&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Current System State ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Before discussing reports it seems appropriate to describe how the system state is stored and accessed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - OCEOS and the Application software'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For OCEOS this is given by its fixed data area, its dynamic data area, and its log data area. Also by some heap items and the stack and registers, including the PC. The latter are also relevant to the application state.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The locations and sizes of three OCEOS areas are determined by the application. Their lay-outs are known. A meta-data structure in the fixed area provides pointers to the principal fields within each data area and simplifies access by OCEOS and by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The three OCEOS areas are available for inspection after OCEOS exits and before it restarts as well as while it is running. This helps after a restart in assessing what went wrong, as well as allowing an application check for lurking problems while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(OCEOS does not allow tasks etc. be created once scheduling has begun, and as a result does not need to use dynamic memory allocation. The memory areas it uses can thus be fixed in advance, their locations and sizes determined by the application.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The task information items mentioned above are automatically updated by OCEOS in the dynamic data area and can be accessed by the application at any time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system state variable contains flags that indicate a certain problem has occurred. It is automatically updated by OCEOS using ‘OR’ to avoiding losing information, typically a user defined function is called to deal with the problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two sets of flags are kept as part of the system state variable. One accumulates indicators of all problems that have occurred, and typically is reset by the application only after a restart. The other indicates current problems, and typically is reset by the user defined problem handling function.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system log records when, what, and in some cases where something occurred. It is automatically written to by OCEOS in certain conditions and can also be read and written by the application. (Codes for what from 0x80 to 0xff are reserved for use by OCEOS, codes 0 to 0x7f are available for use by the application. At present only 24 bits are used to indicate where, this can be expanded to e.g. include the PC or stack pointer.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;At present the log area contains the system state variable as well as the system log. The system state variable could equally well be stored in the dynamic data area.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - Hardware'':&lt;br /&gt;
&lt;br /&gt;
Registers&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 has 504 32-bit IU registers, organized in 31 windows. In addition there are the usual processor registers PC, SP, Y, %psr, %wim and %tbr, and ancillary state registers %asr16, %asr17, %asr20, %asr22-23, %asr24-31. There are also 32 floating point registers, each 32-bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Other units with registers that have a key role in determining the current hardware state include the interrupt controller, the clock gating units, the EDAC and memory scrubber units, and the statistics unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;After a reset registers may have been automatically reset to some initial value and their previous content lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EDAC&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The internal data and instruction RAMs and the external RAM have individual EDAC and scrubber units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Normally the scrubber units will be configured to cycle through the memory, reading each location and writing it back if an error is detected, thus helping reduce the likelihood of a double bit error.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a double bit error is detected, the scrubber units can be configured to halt with the current address in a scrubber register and generate an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The two scrubbers for the internal memory each have a 4-bit counter (ECNT) for the number of single bit errors corrected. This can be reset by writing 0 to it. Correctable errors do not cause an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The external scrubber unit counts both correctable and un-correctable errors it has encountered, and allows thresholds be set for each of these so that an interrupt is generated if either threshold is exceeded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;EDAC errors give rise to an interrupt on interrupt line 63 which is mapped by default to interrupt 19. A handler for this interrupt needs to be put in place by the ASW as what should be done depends on the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;if set up appropriately the EDAC system can also be used to get an indication of background radiation levels by periodically checking the number of single bit errors that have been corrected in a given time period. Again should be done, if required, by the ASW.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reporting====&lt;br /&gt;
&lt;br /&gt;
Two main types of report&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current system state, including checking for potential problems&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;System state when a problem has occurred&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Non-fatal problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Reporting the Current System State''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As all OCEOS data is readily available, and the application itself is running in kernel/supervisor mode and is able to access all registers, there is no obvious help required from OCEOS to enable an application analyse the current state of the system whenever it wishes and report on this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A different question is what conditions OCEOS itself should monitor and bring to the attention of the application so that the application can take action and perhaps prevent the emergence of a problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The standard OCEOS mechanism for bringing an anomaly to the attention of the application is to call a user defined problem handling function after updating the system state variable and making a system log entry.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
The question then becomes in what circumstances OCEOS should do this.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS will always notify the application if it detects a problem such as a task using a mutex whose ceiling is lower than the task’s priority (an application configuration error), or a task exiting while holding a mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, a deadline for the task (number of microseconds after request to start by which it should have completed) can be specified. OCEOS can automatically notify the application if a task has missed its deadline. Or alternatively, if the time when a task completed was dangerously close to its deadline.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, an expected minimum time between task start requests can be specified. OCEOS can automatically notify the application if a start request occurs sooner than this, or alternatively if the time between start requests was too close to the expected value.??&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
OCEOS can check the state of the system when it does a context switch, or when any of its directives are used, or when it performs a timed action. (Unlike many operating systems OCEOS does not depend on a regular timer tick interrupt.)&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
''Reporting System State after a problem has occurred''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the problem is non-fatal, so that OCEOS can continue, when OCEOS detects the problem it will call the user defined problem handling function after updating the system state variable and system log.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU continues to function but OCEOS cannot continue, e.g. due to an OCEOS data area being corrupted by the application, OCEOS will exit. The application can consult the OCEOS data areas and various hardware registers to determine why OCEOS had to exit. It can then restart OCEOS.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU itself must shut down, and warning is given of this before it must happen by e.g. a brown-out detector, then two reports are involved&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a short death report for use before the CPU shuts down&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a long death report put together after the system restarts&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Usually generated in an interrupt handler (e.g. brown-out detected)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The type of problem is identified by the interrupt caused&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS does not seem to have any role in reading registers, whether in EDAC or scrubber units or elsewhere, simpler to just read them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Same applies to system time if needed, just requires a timer register read.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current task and job (equivalent of thread) can be stored by OCEOS in same area as OCEOS system state variable to make both readable as one block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Other items that might be stored in this block by OCEOS include&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;system priority ceiling (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;interrupt nesting level (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on ready queue (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;current number of mutexes held (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on counting semaphore pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on data queue pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of actions on timed actions queue (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The interrupt handler might also store items in the block, e.g.&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;PC when the interrupt was called&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Stack pointer&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;EDAC/scrubber registers&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS can keep the block up to date each time a new job begins executing (not done at present but no problem). But just what should the block include??&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The block data will be preserved across resets depending on the memory used. If this is non-volatile it will be preserved across power fail/restore cycles, and accessible in creating the long death report after restart.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Don’t think OCEOS has a role in relation to the line or function where the error happened (using GCC/LLVM predefined macros, such as __LINE__)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;What other OCEOS summary information if any should kept in the quick death report data block? (The detailed information on task times etc are accessible but probably too much for the short death report.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; The application chooses the memory to be used for the OCEOS dynamic area and for the OCEOS log area. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If both of these are non-volatile a very detailed description of the state of the system when the reset occurred is available to the application after the restart and can be used by it to generate a report before it restarts OCEOS (which will overwrite the dynamic area).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the short death report block is stored in one of these areas it will also be available.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the two areas are volatile the above will still be true but only for resets that did not involve power failure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the areas are in GR716 internal memory the GR716 boot sequence needs to be taken into account. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; After a reset it is likely that register contents, whether in the CPU or elsewhere, will not have been preserved. This is true a fortiori if the reset was caused by a power failure. Critical register information, such as the PC and stack pointer, will need to be captured in the quick death report data block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Changing the default trap handler====&lt;br /&gt;
&lt;br /&gt;
The default trap handler provided by BCC may be changed by modifying trap_table_svt_tables.S provided with BCC. The default BCC trap handler __bcc_trap_table_svt_bad should be replaced with the ASW trap handler or the OCEOS default trap handler (__oceos_default_trap_handler) provided in the example applications (shown below). The application should now be recompiled and linked with the new trap_table_svt_tables.S. When application starts, all trap handlers will be in memory ready for use by the application.&lt;br /&gt;
&lt;br /&gt;
 /** &lt;br /&gt;
 * OCEOS default trap handler. &lt;br /&gt;
 */ &lt;br /&gt;
 void __oceos_default_trap_handler () &lt;br /&gt;
 { &lt;br /&gt;
   U32_t tt; &lt;br /&gt;
   __asm__ volatile ( &amp;quot;mov %%tbr, %0&amp;quot; : &amp;quot;=&amp;amp;r&amp;quot; (tt));&lt;br /&gt;
   tt = (tt &amp;amp; 0xff0) &amp;gt;&amp;gt; 4; &lt;br /&gt;
   // Log ERROR and return &lt;br /&gt;
   oceos_log_add_entry(LOG_SYSTEM_ERROR, tt); &lt;br /&gt;
   // Update System Variable &lt;br /&gt;
   U32_t current_state = oceos_system_state_get(); &lt;br /&gt;
   current_state |= STATUS_SYSTEM_ERROR; &lt;br /&gt;
   oceos_system_state_set(current_state); &lt;br /&gt;
   __asm__ volatile (&amp;quot;restore&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;jmp %l2&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;rett %l2 + 0x4&amp;quot;); &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Context Switch Logging ==&lt;br /&gt;
&lt;br /&gt;
'''Basic approach:'''&lt;br /&gt;
&lt;br /&gt;
If enabled, each time a context switch or interrupt occurs four 32-bit words are added to the context switch log.&lt;br /&gt;
&lt;br /&gt;
The first of these describes the type of switch and also gives the current window pointer (CWP) and the low 8 bits of the high 32 bits of the 64-bit system time when the switch occurred.&lt;br /&gt;
The second gives the 32-bit system time in microseconds at which the switch occurred.&lt;br /&gt;
&lt;br /&gt;
The third gives the start delay if a task is being started, otherwise a signed int giving the remaining time until the deadline or INT_MAX if the task has no deadline, a negative value gives by how much the deadline has been missed.&lt;br /&gt;
The fourth gives the current system stack pointer. &lt;br /&gt;
&lt;br /&gt;
The user specifies the number of entries in the context switch log in the application configuration. This size is given as a number in the range 3 to 12, resulting in from 2^3 to 2^12 entries. If a size outside this range is specified no context switch log is present (no header and no entries).&lt;br /&gt;
&lt;br /&gt;
If valid the size is stored in sysMetaPtr-&amp;gt;CS_log_entries_base2. If invalid this holds 0, CS logging is off.&lt;br /&gt;
&lt;br /&gt;
'''CS Log Structure:'''&lt;br /&gt;
&lt;br /&gt;
CS Header followed by circular buffer, each buffer entry four 32-bit words.&lt;br /&gt;
&lt;br /&gt;
''Switch information (first word):''&lt;br /&gt;
&lt;br /&gt;
*8 bits high time bits (31 to 24)&lt;br /&gt;
*5 bits CWP  (23 to 19)							  	      &lt;br /&gt;
*1 bit (18) switch type,  0=&amp;gt; starting, 1 =&amp;gt; interrupt or ending 				      &lt;br /&gt;
*1 bit (17) ‘from’ ID type, 0=&amp;gt; from task, 1 =&amp;gt; from interrupt				      &lt;br /&gt;
*1 bit (16) ‘to’ ID type, 0 =&amp;gt; to task, 1 =&amp;gt; to interrupt					      &lt;br /&gt;
*8 bits (15 to 8) ID of task/interrupt from which switching				      &lt;br /&gt;
*8 bits (7 to 0) ID of task/interrupt to which switching&lt;br /&gt;
 &lt;br /&gt;
:TASK_ID_INVALID (0xff) is used to indicate switching to or from the scheduler itself. 	  The interrupt ID 0 is not expected to occur, used as TO when CPU put to sleep	     Initialised by oceos_start() to 0x0000ffff (invalid as scheduler doesn’t switch to itself).&lt;br /&gt;
&lt;br /&gt;
''Context switch time word (second word):''&lt;br /&gt;
&lt;br /&gt;
:Low 32 bits of the time at which switch happened. The next 8 bits of the 64-bit system time are given in the switch information word, giving an overall 40-bit time value. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''Start wait time / deadline time margin word (third word):''&lt;br /&gt;
&lt;br /&gt;
:When first starting a task, the delay between the start request and execution beginning. Otherwise a signed int giving remaining time until deadline or 0x7fffffff if no deadline. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''System stack pointer (fourth word):''&lt;br /&gt;
&lt;br /&gt;
:System stack pointer when switch was made. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
'''Storage:'''&lt;br /&gt;
&lt;br /&gt;
Stored in log area immediately after last system log entry and before END_SENTINEL for log area.&lt;br /&gt;
&lt;br /&gt;
Space needed for CS log is included in log area size recorded at the start of the log area.&lt;br /&gt;
&lt;br /&gt;
Number of CS log entries is 2^size unless size is invalid, in which case no storage is used.&lt;br /&gt;
&lt;br /&gt;
If sysMetaPtr-&amp;gt;CS_log_entries_base2 is outside the allowed range (typically 0) no context switch logging is done. The CS header is not present, END_SENTINEL is at that position instead.&lt;br /&gt;
&lt;br /&gt;
== Recover runs ==&lt;br /&gt;
&lt;br /&gt;
The previous section describes the error diagnostic facilities provided by OCEOS. The recovery procedure is the responsibility of the application. In the worst case a system reset can be initiated by the application. The table below shows some failure modes and recommended actions to recover.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;text-align:left;&amp;quot;| SFMEA ID&lt;br /&gt;
! Failure cause&lt;br /&gt;
! Recommended action&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0010&lt;br /&gt;
|ASW sets up a non-schedulable set of tasks&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0020&lt;br /&gt;
|ASW sets up a task that may demands excessive CPU or Memory resources&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom and map file to view memory usage&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0040&lt;br /&gt;
|Human error in OCEOS code&lt;br /&gt;
|Email details to support@ocetechnology.com&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0045&lt;br /&gt;
|Divide by zero occurs in OCEOS or in ASW.&lt;br /&gt;
|ASW to implement user defined trap&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0060&lt;br /&gt;
|Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW should use EDAC scrubber to correct error and report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0070&lt;br /&gt;
|Single Event Upset, permanent (burnt bit) in RAM&lt;br /&gt;
|ASW to refactor memory location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0080&lt;br /&gt;
|Single Event Upset, temporary in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to rewrite PROM location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0090&lt;br /&gt;
|Single Event Upset, permanent (burnt-proton impact etc) in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to set indicator to boot from backup image&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0100&lt;br /&gt;
|Double bit Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW to initiate warm or cold restart&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0110&lt;br /&gt;
|RAM memory corruption by any reason e.g. incorrect write address&lt;br /&gt;
|ASW dependent but warm or cold restart are options&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.16FM-0&lt;br /&gt;
|continuous false alarm&lt;br /&gt;
|ASW to reduce alarm check interval amd mark as ignore&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0130&lt;br /&gt;
|deadlock occurs&lt;br /&gt;
|Deadlock cannot occur from OCEOS directives&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0140&lt;br /&gt;
|clock corrupted, frozen or rate drifts (HSIA crystal failure)&lt;br /&gt;
|ASW to trigger watchfod restart and report issue&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0150&lt;br /&gt;
|output before required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0160&lt;br /&gt;
|output after required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=705</id>
		<title>OCEOS Operation</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=705"/>
		<updated>2021-10-01T12:26:29Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Building the example application */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Operations basics =&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library, header files(s), and application source files that can be compiled and linked with the standard BCC gcc or clang tools and libraries to provide a real-time multitasking application. OCEOS uses BCC library calls for some system functions. These functions are provided in the BCC board support package for the GR716. The minimum memory footprint for OCEOS is shown in the table below. Core modules occupy less than 10K bytes.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_size.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Operations manual =&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is structured as a set of managers each providing OCEOS service calls. &amp;lt;/br&amp;gt;&lt;br /&gt;
The activities supported by these managers are: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|''''' Initialization manager ''''':&lt;br /&gt;
|initializing the hardware and OCEOS itself&lt;br /&gt;
|-&lt;br /&gt;
|''''' Task manager ''''':&lt;br /&gt;
|handling tasks and jobs, including scheduling&lt;br /&gt;
|-&lt;br /&gt;
|''''' Interrupt manager ''''':&lt;br /&gt;
|setting up trap handlers&lt;br /&gt;
|-&lt;br /&gt;
|''''' Clock manager ''''':&lt;br /&gt;
|providing time of day, dates, and alarms&lt;br /&gt;
|-&lt;br /&gt;
|''''' Timer manager ''''':&lt;br /&gt;
|interval timing and alarms, timed outputs and jobs&lt;br /&gt;
|-&lt;br /&gt;
|''''' Mutex manager ''''':&lt;br /&gt;
|mutual exclusion management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Semaphore manager ''''':&lt;br /&gt;
|counting semaphore management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Data queue manager ''''':&lt;br /&gt;
|data queue management&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The directives provided by these managers are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== Set‐up and initialisation ==&lt;br /&gt;
&lt;br /&gt;
Setup for the use of OCEOS requires the user to prepare the development environment.&lt;br /&gt;
At a minimum this requires the installation for compilers, debug tool, editors, …etc.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
=== DMON OCEOS Support===&lt;br /&gt;
:OCE added OCEOS support to DMON to help user in debugging application software. Detailed manual and available functionality can be found [[DMON_OCEOS_Support|'''here''']].&lt;br /&gt;
&lt;br /&gt;
[[File:Cpu_load_main.png|600px|Cpu Load View]] [[File:Cpu_profile_main.png|600px|Cpu Profile View]]&lt;br /&gt;
&lt;br /&gt;
=== Files provided with OCEOS ===&lt;br /&gt;
&lt;br /&gt;
Unpack the OCEOS software into an appropriate folder on the computer. The folders are as follows:&lt;br /&gt;
&lt;br /&gt;
[[File:unzip_folders.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Documentation OCEOS User Manual and Quick Reference.&lt;br /&gt;
* include Include files required by the application&lt;br /&gt;
* OCEOS_GCC_LIB oceos.a object library for applications to be built with gcc&lt;br /&gt;
* OCEOS_LLNM_LIB oceos.a object library for applications to be built with llvm (32-bit)&lt;br /&gt;
* OCEOS_LLVM_REX_LIB oceos.a object library for applications to be built with llvm (16-bit REX mode)&lt;br /&gt;
* Sample Project c sources, include files, and make files for an example project&lt;br /&gt;
* UserManualTutorials c sources, include files, and make files for User Manual tutorials and application example &lt;br /&gt;
* Excel configuration file to help produce oceos_config.h can be downloaded from [[Media:OCEOS_Config.xlsx]] &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The source and build files associated with the example application referred to in this manual are located in the folder &amp;lt;installation-folder&amp;gt; \UserManualTutorials\asw.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''asw.h''' &amp;lt;blockquote&amp;gt;Simple application header.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''asw.c''' &amp;lt;blockquote&amp;gt;Simple application example. This file is a self-contained example of an OCEOS application including tasks, mutexes, semaphores, and dataqueues.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''oceos_config.h''' &amp;lt;blockquote&amp;gt;This is the OCEOS application header file where the developer specifies the number of tasks, mutexes, sempahores, dataqs, log entries, and readyq entries. These numbers are used to allocate the &lt;br /&gt;
memory required for storing oceos variables. The definitions to be specified follow.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_configuration2.jpg]]&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
Notes: &amp;lt;/br&amp;gt;&lt;br /&gt;
# The application must create the number of tasks, mutexes, semaphores or dataqs specified in this header, otherwise an error will be returned from oceos_init_finish().&lt;br /&gt;
# LOG_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# FIXED_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# DYN_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# Enumerated types are recommended for names of tasks, mutexes, semaphores and dataqs. This header file contains some examples.&lt;br /&gt;
&lt;br /&gt;
'''oceos_config.c''' &amp;lt;blockquote&amp;gt;This file contains the OCEOS data areas and the following functions:&lt;br /&gt;
# int application_init() This function initialises the oceos data area.&lt;br /&gt;
# void oceos_on_error(void* ptr) The developer should code this function to implement actions in case of a system error.&lt;br /&gt;
# void oceos_on_full_log(void* ptr)&lt;br /&gt;
The developer should code this function which is called when the system log is two-thirds full.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''makefile &amp;amp; makefile.mk''' &amp;lt;blockquote&amp;gt;These file are provided to facilitate building the asw application. Some local edits are required to point to the local compiler folders.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building the example application ===&lt;br /&gt;
&lt;br /&gt;
Download and install the BCC2 compiler [https://www.gaisler.com/index.php/downloads/compilers from here]. &lt;br /&gt;
&lt;br /&gt;
Use the Makefile provided or use the following commands to compile and link the application.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c asw.c -o asw.o&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c oceos_config.c -o oceos_config.o&lt;br /&gt;
&lt;br /&gt;
 sparc-gaisler-elf-clang asw.o oceos_config.o -o asw-gr716.elf -qbsp=gr716 -mcpu=leon3 -qsvt -qnano -Wall -LC:/projects/oce/oceos/trunk/oceos_product/oceoc/build/ -loceos -Wl,-Map=asw-gr716.map&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
# sparc-gaisler-elf-clang Ensure the path to the compiler has been configured. The llvm clang compiler is recommended as the OCEOS library was compiled with it.&lt;br /&gt;
# -I. -Iinclude -I&amp;lt;bcc-install-folder&amp;gt;/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include This -I option allows paths to include files to be passed to the compiler.&lt;br /&gt;
# -qbsp=gr716 This option specifies the compiler gr716 board support package.&lt;br /&gt;
# -mcpu=leon3 This option specifies the processor type.&lt;br /&gt;
# -Wall Display all warning messages.&lt;br /&gt;
# -c Compile only (linking not required).&lt;br /&gt;
# -o &amp;lt;filename&amp;gt; Specify the output filename.&lt;br /&gt;
# -qsvt Use the single-vector trap model described in “SPARC-V8 Supplement, SPARC-V8 Embedded (V8E) Architecture Specification”.&lt;br /&gt;
# -qnano Use a version of the newlib C library compiled for reduced foot print. The nano version implementations of the fprintf() fscanf() family of functions are not fully C standard compliant. Code size can decrease with up to # KiB when printf() is used.&lt;br /&gt;
# -L&amp;lt;path-to-oceos-library-file&amp;gt; Specify the path where liboceos.a is located.&lt;br /&gt;
# -loceos Instructs linker to use library liboceos.a&lt;br /&gt;
# -Wl,-Map=asw-gr716.map Instructs the linker to generate a map file with the name asw-gr716.map. This optional map file details the memory map of all functions and data.&lt;br /&gt;
# Consult the BCC manual for other options.&lt;br /&gt;
&lt;br /&gt;
The application executable (in this case asw.elf) can now be downloaded and executed on the target GR716 hardware. A debug tool such as DMON or GRMON is required for this. DMON provides specific support of OCEOS.&lt;br /&gt;
&lt;br /&gt;
'''''Important Note'''''&lt;br /&gt;
Up to BCC version 2.1.2 bcc_inline.h needs to be changed as it does not function on the GR716 as expected. The file is located in …\bcc-2.x.x-llvm\sparc-gaisler-elf\bsp\gr716\include\bcc\ for llvm and …\bcc-2.x.x-gcc\sparc-gaisler-elf\bsp\gr716\include\bcc for gcc.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* OCEOS comment out until BCC fix&lt;br /&gt;
 #ifdef __BCC_BSP_HAS_PWRPSR&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         uint32_t ret;&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
               &amp;quot;sll %4, %1, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;or %%o1, %2, %4\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;.word 0x83882000\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;rd %%psr, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;andn %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;wr %4, %%o2, %%psr\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;and %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;srl %%o2, %1, %0\n\t&amp;quot;&lt;br /&gt;
                 : &amp;quot;=r&amp;quot; (ret)&lt;br /&gt;
                 : &amp;quot;i&amp;quot; (PSR_PIL_BIT), &amp;quot;i&amp;quot; (PSR_ET), &amp;quot;i&amp;quot; (PSR_PIL), &amp;quot;r&amp;quot; &lt;br /&gt;
 (newpil)&lt;br /&gt;
                 : &amp;quot;o1&amp;quot;, &amp;quot;o2&amp;quot;&lt;br /&gt;
         );&lt;br /&gt;
         return ret;&lt;br /&gt;
 }&lt;br /&gt;
 #else &lt;br /&gt;
 */&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         register uint32_t _val __asm__(&amp;quot;o0&amp;quot;) = newpil;&lt;br /&gt;
         /* NOTE: nop for GRLIB-TN-0018 */&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
                 &amp;quot;ta %1\nnop\n&amp;quot; :&lt;br /&gt;
                 &amp;quot;=r&amp;quot; (_val) :&lt;br /&gt;
                 &amp;quot;i&amp;quot; (BCC_SW_TRAP_SET_PIL), &amp;quot;r&amp;quot; (_val)&lt;br /&gt;
         );&lt;br /&gt;
         return _val;&lt;br /&gt;
 } &lt;br /&gt;
 /* For OCEOS &lt;br /&gt;
 #endif&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If bcc_inline.h is not modified traps may be left disabled or in REX mode an illegal opcode trap is generated. [GRLIB]&lt;br /&gt;
&lt;br /&gt;
== Mode selection and control ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library with header files for applications wishing to use it. There are two primary modes of operation on the GR716 as follows:&lt;br /&gt;
* SPARC V8 32-bit Mode &amp;lt;/br&amp;gt; 32-bit mode is the standard instruction word size on the SPARC V8. An OCEOS object library is provided for 32-bit mode (gcc &amp;amp; llvm)&lt;br /&gt;
* REX 16-bit mode &amp;lt;/br&amp;gt; REX mode allows the GR716 to execute 16-bit instructions. Applications running in rex mode occupy a smaller memory footprint. The compiler option -mrex should be used and -Oz for the smallest footprint.&lt;br /&gt;
&lt;br /&gt;
It is an application design choice as to which mode is used.&lt;br /&gt;
&lt;br /&gt;
== Normal operations ==&lt;br /&gt;
&lt;br /&gt;
This section describes the OCEOS directives used to in most applications. See file asw.c for example.&lt;br /&gt;
&lt;br /&gt;
The calls to get OCEOS running are:&lt;br /&gt;
&lt;br /&gt;
# application_init – uses oceoc_init to Initialise fixed data and start system time and log&lt;br /&gt;
# oceos_task_create - Create task setting priority, no of jobs, ..etc.&lt;br /&gt;
# oceos_init_finish – Initilise dynamic data area&lt;br /&gt;
# oceos_start – Start the scheduler and pass control to first task&lt;br /&gt;
&lt;br /&gt;
After steps 1 to 4 above tasks implement application functionality. If mutexes, semaphores, dataqs and/or timed actions are required they also are created at step 2. &amp;lt;/br&amp;gt;&lt;br /&gt;
Note: it is mandatory to create the number of mutexes, semaphores, and dataqs declared otherwise oceos_init_finish() will return an error.&lt;br /&gt;
&lt;br /&gt;
=== application_init() ===&lt;br /&gt;
&lt;br /&gt;
[[File:application_init.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create (…) ===&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
oceos_task_create prepares a task for execution. In the case above the parameters are:&lt;br /&gt;
* t_setup is an integer setup in the enumerated type in oceos_config.h. t_setup is used to identify this task to OCEOS thereafter. &lt;br /&gt;
[[File:enum_task_name.jpg]]&lt;br /&gt;
* 3 is the priority allocated to this task. 1 is the highest and 254 the lowest priority&lt;br /&gt;
* 3 is the priority threshold. The scheduler will only allow tasks higher than this priority to pre-empt task t_setup.&lt;br /&gt;
* 1 is the maximum number of jobs for task t_setup. 15 is the maximum number of jobs that can be ready-to-run for any task.&lt;br /&gt;
* 0 indicating that floating point is not used by this task. Enabling floating point for a task causes the scheduler to store all floating point registers on the stack when the job is pre-empted. If the job is not using floating point this causes inefficiency.&lt;br /&gt;
* 1 causes the task to be enabled on when oceos is started.&lt;br /&gt;
* setup_start is the name of the function to be executed for this task. The code for setup_start is in asw.c and the function declared in asw.h.&lt;br /&gt;
[[File:setup_start.jpg]]&lt;br /&gt;
* setup_end is the function called when task t_setup terminates.&lt;br /&gt;
[[File:setup_end.jpg]]&lt;br /&gt;
* 0 instructs the scheduler that there is no maximum execution time for this task. If a value (in microseconds) is specified the scheduer will raise an error if the task exceeds this execution time.&lt;br /&gt;
* 0 instructs the scheduler that there is no minimum time between executions of this task. If a time in microseconds is specified the scheduler will raise an error if this value is violated.&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish() ===&lt;br /&gt;
This function must be called before OCEOS is started. It completes the initialisation of OCEOS data for the application.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_init_finish.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_start() ===&lt;br /&gt;
&lt;br /&gt;
This function starts task scheduling in OCEOS. It should never return from this function.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters passed to oceos_start are:&lt;br /&gt;
* fixed_data is a pointer to the start of the fixed data area. It is declared in oceos_config.c.&lt;br /&gt;
* t_setup is the ID of the task to be set executing when OCEOS starts (in oceos_config.h).&lt;br /&gt;
* Optional pointer that will be passed to the task started, here t_setup.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive starts an instance of a task, called a job in OCEOS. In this case start means puts an instance of the task, a job, on the ready-to-run queue, and performs a reschedule.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; If it is the highest priority job ready-to-run, it will be set running by the scheduler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The parameters passed to it are the task ID and a pointer. It returns an integer indicating the status of the call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many cases the first task to be run by OCEOS will perform application initialisation and then start the other application tasks including the idle task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex. It must be called before oceos_init_finish(). Parameters passed are the mutex ID and the priority ceiling for the mutex.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling is the priority of the highest task that uses the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note that the user must determine this priority ceiling as part of the application design. &lt;br /&gt;
OCEOS relies on the developer to specify the correct priority ceiling.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive assigns the mutex to the calling job. It should always be successful because a job should only be set running if the mutex is available to it.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_wait.jpg]]&lt;br /&gt;
&lt;br /&gt;
The mutex ID is the only parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive releases a mutex from a job. It will cause a reschedule and if a higher priority job has been waiting on the mutex it will start causing this job to be pre-empted.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The only parameter to the directive is the mutex ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a counting semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_create2.jpg |700px]]&lt;br /&gt;
&lt;br /&gt;
* Semaphore ID (0 to 62)&lt;br /&gt;
* Maximum No of permits (1 to 4094)&lt;br /&gt;
* Starting number of permits (1 to 4094)&lt;br /&gt;
* Maximum number of jobs on this semaphore queue (1 to 254)&lt;br /&gt;
* Whether timeout is used in oceos_sem_wait_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameter is:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted.&lt;br /&gt;
If a timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart_timeout.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer, long long)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive increments (signals) the specified semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_sem_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The semaphore ID is the sole parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a data queue with specified ID&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_create2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Data Queue Size (1 to 255)&lt;br /&gt;
* Data Queue maximum number of pending jobs (1 to 255)&lt;br /&gt;
* Data Queue roll-overs enable/disable (0 or 1)&lt;br /&gt;
* Whether timeout is used in oceos_dataq_read_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A timeout in microseconds can be set, after which the task will not be restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart_timeout2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive puts a pointer on the specified data queue.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_dataq_write.jpg]]&lt;br /&gt;
&lt;br /&gt;
Parameters are :&lt;br /&gt;
* Data queue ID (0 to 62)&lt;br /&gt;
* Pointer to be put on queue (void *ptr)&lt;br /&gt;
&lt;br /&gt;
== Normal termination ==&lt;br /&gt;
&lt;br /&gt;
It is not normal for OCEOS to terminate. Application tasks usually continue to execute without stopping. If all tasks terminate the system goes to sleep mode and only an interrupt can restart activity.&lt;br /&gt;
&lt;br /&gt;
== Error conditions ==&lt;br /&gt;
&lt;br /&gt;
Error conditions are handled in 4 different ways by OCEOS as follows:&lt;br /&gt;
* Directive return codes allowing application take appropriate action&lt;br /&gt;
* The System Log keeps a record of problems and when they occurred&lt;br /&gt;
* The System State variable indicates the current state of OCEOS&lt;br /&gt;
* The watchdog provides a fallback reset in unpredictable situations&lt;br /&gt;
&lt;br /&gt;
=== Directive return codes ===&lt;br /&gt;
&lt;br /&gt;
OCEOS is driven by directives described in the Reference section below. All directives return a status to be checked by the application. The directive return status is either success or a code indicating why it failed. The table below is taken from oceos.h. It is the responsibility of the application to take appropriate action if a directive call fails.&lt;br /&gt;
&lt;br /&gt;
[[File:Enum_directive_status2.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== The System Log ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;When a problem arises, either in application code or in OCEOS itself, it is useful to have a record of &amp;lt;/p&amp;gt;&lt;br /&gt;
# '''when''' it happened&lt;br /&gt;
# '''what''' kind of problem it was&lt;br /&gt;
# '''where''' it happened.&lt;br /&gt;
&amp;lt;p&amp;gt;The primary purpose of the System Log is to provide this ‘when’, ‘what’, and ‘where’ information.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It does so as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''when''':   the low 32-bits of the system time are automatically recorded when a log entry is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''what''':   an 8-bit number allows 256 different types of entry be specified. Half of these entry types (0x80 to 0xff) are reserved for internal us in OCEOS. The other 128 entry types (0 to 0x7f) are assigned their meanings by the application. (An OCEOS internal code reserved for that purpose is used if an application attempts to use an OCEOS internal code.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''where''':  a 24-bit number is included in each log entry. OCEOS itself uses this to indicate the OCEOS function where the log entry call was made and other information. Application code can use this number in whatever way is appropriate for the application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The log is located in the log area. This area starts at an address specified by the application developer, begins with a 32-bit constant sentinel value followed by a 32-bit count of the number of 32-bit words making up the area (including the sentinels) and ends with a 32-bit constant sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As frequent access to the log area is not likely to be needed the log area can be located in memory external to the GR716. The log area contents will then usually be preserved across system resets, and across system power on/off cycles if the external memory is non-volatile.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The log is structured as a circular buffer, with its read and write indices also stored in the log area. It is set up initially by oceos_init(). This does not overwrite the data currently in the log but resets the read and write indices to be equal and as far as can be determined after the most recent log entry. As the log indices are equal the log now appears empty when an attempt to read it in the usual way is made, but a special directive allows the application program read the data at any position in the log. Another directive allows the application reset all log entries.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Any system that uses OCEOS must have a system log. The number of entries in the log is specified in the system configuration structure, and must be within the specified range or 0, in which case a default value is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The header file oceos.h gives the structure of the log area and the values of the associated constants.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 struct log_entry{&lt;br /&gt;
  U32_t time32;&lt;br /&gt;
  unsigned int entry_type :8;&lt;br /&gt;
  unsigned int entry_comment :24;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
 * Log entry types used when creating a log entry (8 bits, from 0 to 255 only)&lt;br /&gt;
 */&lt;br /&gt;
 enum LOG_ENTRY_TYPE{&lt;br /&gt;
  LOG_SYS_OK = 0x80U,&lt;br /&gt;
  LOG_NULL_FATAL,&lt;br /&gt;
  LOG_OCEOS_ABORT,&lt;br /&gt;
  LOG_INVALID_SYSTEM_STATE,&lt;br /&gt;
  LOG_LOG_NOT_VALID_ENTRY,&lt;br /&gt;
  LOG_STATUS_INVALID,&lt;br /&gt;
  LOG_NULL_POINTER,&lt;br /&gt;
  LOG_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_FREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_UNFREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_RESET_FAIL,&lt;br /&gt;
  LOG_TIME_SCALER_FAIL,&lt;br /&gt;
  LOG_TIME_RELOAD_FAIL,&lt;br /&gt;
  LOG_TIME_COUNTER_FAIL,&lt;br /&gt;
  LOG_TIME_CONTROL_FAIL,&lt;br /&gt;
  LOG_TIME_POINTER_NULL,&lt;br /&gt;
  LOG_TIME_POINTER_LOW_NULL,&lt;br /&gt;
  LOG_TIME_START_FAIL,&lt;br /&gt;
  LOG_FIXED_INIT_FAIL,&lt;br /&gt;
  LOG_DYNAMIC_INIT_FAIL,&lt;br /&gt;
  LOG_INIT_TASK_START_FAIL,&lt;br /&gt;
  LOG_DEADLINE_MISSED,&lt;br /&gt;
  LOG_TASK_DISABLED,&lt;br /&gt;
  LOG_TASK_ENABLED,&lt;br /&gt;
  LOG_JOB_INVALID,&lt;br /&gt;
  LOG_JOB_NONE_FREE,&lt;br /&gt;
  LOG_JOB_NOT_EXECUTING,&lt;br /&gt;
  LOG_JOB_NOT_ACTIVE,&lt;br /&gt;
  LOG_READYQ_TOO_BIG,&lt;br /&gt;
  LOG_READYQ_SENTINEL_BAD,&lt;br /&gt;
  LOG_READYQ_FULL,&lt;br /&gt;
  LOG_READYQ_EMPTY,&lt;br /&gt;
  LOG_READYQ_PUT_DISABLED_TASK,&lt;br /&gt;
  LOG_READYQ_PUT_FAIL,&lt;br /&gt;
  LOG_READYQ_REMOVE_DONE,&lt;br /&gt;
  LOG_READYQ_REMOVE_FAIL,&lt;br /&gt;
  LOG_PARAM_BAD_ID,&lt;br /&gt;
  LOG_PARAM_BAD_TIME,&lt;br /&gt;
  LOG_PARAM_ACTION_MISSING,&lt;br /&gt;
  LOG_PARAM_JOB_MISSING,&lt;br /&gt;
  LOG_MUTEX_BAD_CEILING,&lt;br /&gt;
  LOG_MUTEX_ALREADY_HELD,&lt;br /&gt;
  LOG_MUTEX_ALREADY_FREE,&lt;br /&gt;
  LOG_MUTEX_WRONG_JOB,&lt;br /&gt;
  LOG_MUTEX_NESTING_BAD,&lt;br /&gt;
  LOG_MUTEX_EXIT_HOLDING,&lt;br /&gt;
  LOG_SEMAPHORE_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_SEMAPHORE_MAX_ALREADY_REACHED,&lt;br /&gt;
  LOG_SEMAPHORE_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_TIMED_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_TRANSFER_READYQ_FAIL,&lt;br /&gt;
  LOG_DATAQ_FULL,&lt;br /&gt;
  LOG_DATAQ_EMPTY,&lt;br /&gt;
  LOG_DATAQ_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_DATAQ_PENDING_QUEUE_FULL,&lt;br /&gt;
  LOG_DATAQ_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_DATAQ_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_DATAQ_TIMED_JOB_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_NULL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_STOP_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_NOT_INIT,&lt;br /&gt;
  LOG_TIMED_ACTION_INT_REG_FAILED,&lt;br /&gt;
  LOG_TIMED_ACTION_INVALID,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_INDEX,&lt;br /&gt;
  LOG_TIMED_ACTION_MISSED,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_FULL,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_EMPTY,&lt;br /&gt;
  LOG_TIMED_ACTION_PUT_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_JOB_ID,&lt;br /&gt;
  LOG_TIMED_ACTION_DO_FAIL,&lt;br /&gt;
  LOG_SYSTEM_ERROR,&lt;br /&gt;
  LOG_TIME_BSP_SYSFREQ_NULL,&lt;br /&gt;
  LOG_SEMAPHORE_TIMEOUT_NOT_INIT,  &lt;br /&gt;
  LOG_DATAQ_TIMEOUT_NOT_INIT, &lt;br /&gt;
  LOG_TIMED_ACTION_START_WHILE_RUNNING,&lt;br /&gt;
  LOG_INT_HANDLER_IS_NULL,&lt;br /&gt;
  LOG_SET_OCEOS_TRAP_HANDLER_FAILED,&lt;br /&gt;
  LOG_INT_CALLED_NO_INIT,&lt;br /&gt;
  LOG_FAILED_SET_INT_PRIO,  &lt;br /&gt;
  LOG_FAILED_PENDSV_INIT,&lt;br /&gt;
  LOG_SYS_TIME_NOT_INIT    &lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_add_entry(&lt;br /&gt;
 enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
 const unsigned int // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_remove_entry(struct log_entry * const);&lt;br /&gt;
 &lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_get_indexed_entry(&lt;br /&gt;
 const unsigned int,&lt;br /&gt;
 struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
=== The System State variable ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/p&amp;gt;OCEOS maintains a system state variable which shows the current state of the system. States are shown below. If the system state deviates from normal (value 0) the user defined function oceos_on_error(..) is called by OCEOS. The source code for this function is located config.c and should be written by the application developer to take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directives oceos_system_state_get and oceos_system_state_set are provided to allow the application to access the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 void oceos_on_error(void* ptr) { // Application dependent error handling code should be included here&lt;br /&gt;
 return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
 * The 32-bit system state variable indicates the current system state&lt;br /&gt;
 */&lt;br /&gt;
 #define STATUS_NORMAL 0u // System State Normal&lt;br /&gt;
 #define STATUS_EDAC_INTERNAL 1u // Uncorrectable error in internal memory&lt;br /&gt;
 #define STATUS_EDAC_EXTERNAL 2u // Uncorrectable error in external memory&lt;br /&gt;
 #define STATUS_MEM_PROT_1 4u // Invalid access memory protection unit 1&lt;br /&gt;
 #define STATUS_MEM_PROT_2 8u // Invalid access memory protection unit 2&lt;br /&gt;
 #define STATUS_DISABLED_TASK_START 0x10u // An attempt to start a disabled task&lt;br /&gt;
 #define STATUS_TASK_JOB_LIMIT_OVER 0x20u // An attempt to execute a task when its jobs limit is already reached.&lt;br /&gt;
 #define STATUS_JOB_OVER_TIME 0x40u // Job time from creation to completion exceeds allowed maximum for a task.&lt;br /&gt;
 #define STATUS_JOB_INTERVAL_SHORT 0x80u // Minimum time between job creations is less than the allowed minimum for task&lt;br /&gt;
 #define STATUS_READYQ_FULL 0x100u // Ready queue unable to accept job as result of being full&lt;br /&gt;
 #define STATUS_MUTEX_ALREADY_HELD 0x200u // Mutex wait() when mutex already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_HELD 0x400u // Mutex signal() when not already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_RETURNED 0x800u // Mutex not returned before job terminates&lt;br /&gt;
 #define STATUS_SEMAPHORE_JOBS_FULL 0x1000u // Attempt to add job to semaphore pending list when list full&lt;br /&gt;
 #define STATUS_DATAQ_FULL 0x2000u // Data queue write when queue already full&lt;br /&gt;
 #define STATUS_DATAQ_JOBS_FULL 0x4000u // Attempt to add job to queue pending list when list full&lt;br /&gt;
 #define STATUS_TIMED_JOBS_FULL 0x8000u // Timed jobs queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_JOB_LATE 0x10000u // Timed jobs queue late job transfer to scheduler&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_FULL 0x20000u // Timed output queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_LATE 0x40000u // Timed output late&lt;br /&gt;
 #define STATUS_BAD_LOG 0x80000000u // System Log corruption&lt;br /&gt;
 #define STATUS_INVALID 0xffffffffu // Invalid system state&lt;br /&gt;
&lt;br /&gt;
=== The watchdog ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 provides watchdog functionality (ref: GR716 Advanced Data Sheet and User’s Manual). OCEOS provides functions to allow applications to use this watchdog functionality (see section 10 for more details). It is expected that OCEOS applications using the watchdog have a low priority task to continually reset the watchdog timer using the directive oceos_system_watchdog_reset(..). If the watchdog reaches its timeout value this is an indication that a severe error has occurred and a hardware reset is generated by the watchdog unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application when rebooted can optionally check the system log, and last system state to determine the cause of the watchdog reboot and take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hardware errors ===&lt;br /&gt;
&lt;br /&gt;
Hardware errors can come from a number of sources including the following:&lt;br /&gt;
* Uncorrectable memory errors&lt;br /&gt;
* Memory protection violations&lt;br /&gt;
* Brown-out or low power&lt;br /&gt;
The OCEOS philosophy to dealing with these and other hardware faults causing interrupts is to provide directives enabling the application to take appropriate actions. OCEOS directives available for application recovery are:&lt;br /&gt;
* oceos_interrupt_handle_register This directive may be used to setup application recovery interrupt service routines.&lt;br /&gt;
* oceos_exit This directive may be called to exit OCEOS back to the application for appropriate recovery actions.&lt;br /&gt;
* oceos_log_get_indexed_entry This directive may be used as part of the application fault analysis.&lt;br /&gt;
* oceos_system_state_get This action allows the application obtain the system status to determine appropriate recovery action.&lt;br /&gt;
&lt;br /&gt;
=== Overload and system failure ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overloads and system failure are different but have some common features. Both can lead to an unexpected system restart, and to the question ‘what caused that?’. Both can sometimes be anticipated if warning signs are noticed. It may even be possible to avoid them by taking appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Some thoughts and suggestions about them and OCEOS follow below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Overload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overload generally refers to insufficient CPU time to handle a situation.&lt;br /&gt;
Can also be a memory shortage, for example insufficient stack space.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;A task missing a soft deadline - needs to be noted&amp;lt;/li&amp;gt; &lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;A task missing a hard deadline - may be catastrophic&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Watchdog timeout - hardware reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inability to start a task due to memory shortage&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Interrupts more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task pre-empted more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Tasks start requests more frequent than expected&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inappropriate allocation of task priorities&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;One or more tasks using more than the expected CPU time (should not happen)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Holding one or more mutexes for too long&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Using mutexes in a non-nested manner&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Insufficient stack space&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;(With OCEOS unbounded priority inversion cannot occur.)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;(With OCEOS chained blocking cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;(With OCEOS deadlocks cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Information available for comparison to expected values to detect potential overload'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Task maximum duration – job creation time to termination time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task maximum CPU time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Task minimum time between start requests&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Task number of times pre-empted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Task maximum current jobs for a task&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Watchdog timer nearly timed out when reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Stack pointer approaching limit of allowed range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Et alia&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Disable certain interrupts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Disable a task or tasks&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Kill currently executing job&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== System failure ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;System failure generally refers to the CPU ceasing to execute instructions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Can also be a reference to the operating system (OCEOS) having to exit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Usually associated with hardware problems, but software can do it too.&amp;lt;/p&amp;gt;&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;OCEOS exit (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;CPU stops execution (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;A subsequent restart (hopefully)&amp;lt;/li&amp;gt;&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Critical OCEOS data corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Un-correctable memory error&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Memory hardware failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Power failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Environment more demanding than design anticipated causing hardware problems&amp;lt;/li&amp;gt;&lt;br /&gt;
''Warning signs that can indicate something wrong at system level'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Sentinels on OCEOS critical data areas corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Stack pointer approaching limit of range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Corrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Uncorrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Voltage levels - brown out detection interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Use EDAC scrubber units to continually regenerate all RAM&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Use MEMPROT unit to restrict OCEOS fixed data write access to the scrubber only&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Current System State ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Before discussing reports it seems appropriate to describe how the system state is stored and accessed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - OCEOS and the Application software'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For OCEOS this is given by its fixed data area, its dynamic data area, and its log data area. Also by some heap items and the stack and registers, including the PC. The latter are also relevant to the application state.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The locations and sizes of three OCEOS areas are determined by the application. Their lay-outs are known. A meta-data structure in the fixed area provides pointers to the principal fields within each data area and simplifies access by OCEOS and by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The three OCEOS areas are available for inspection after OCEOS exits and before it restarts as well as while it is running. This helps after a restart in assessing what went wrong, as well as allowing an application check for lurking problems while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(OCEOS does not allow tasks etc. be created once scheduling has begun, and as a result does not need to use dynamic memory allocation. The memory areas it uses can thus be fixed in advance, their locations and sizes determined by the application.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The task information items mentioned above are automatically updated by OCEOS in the dynamic data area and can be accessed by the application at any time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system state variable contains flags that indicate a certain problem has occurred. It is automatically updated by OCEOS using ‘OR’ to avoiding losing information, typically a user defined function is called to deal with the problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two sets of flags are kept as part of the system state variable. One accumulates indicators of all problems that have occurred, and typically is reset by the application only after a restart. The other indicates current problems, and typically is reset by the user defined problem handling function.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system log records when, what, and in some cases where something occurred. It is automatically written to by OCEOS in certain conditions and can also be read and written by the application. (Codes for what from 0x80 to 0xff are reserved for use by OCEOS, codes 0 to 0x7f are available for use by the application. At present only 24 bits are used to indicate where, this can be expanded to e.g. include the PC or stack pointer.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;At present the log area contains the system state variable as well as the system log. The system state variable could equally well be stored in the dynamic data area.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - Hardware'':&lt;br /&gt;
&lt;br /&gt;
Registers&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 has 504 32-bit IU registers, organized in 31 windows. In addition there are the usual processor registers PC, SP, Y, %psr, %wim and %tbr, and ancillary state registers %asr16, %asr17, %asr20, %asr22-23, %asr24-31. There are also 32 floating point registers, each 32-bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Other units with registers that have a key role in determining the current hardware state include the interrupt controller, the clock gating units, the EDAC and memory scrubber units, and the statistics unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;After a reset registers may have been automatically reset to some initial value and their previous content lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EDAC&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The internal data and instruction RAMs and the external RAM have individual EDAC and scrubber units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Normally the scrubber units will be configured to cycle through the memory, reading each location and writing it back if an error is detected, thus helping reduce the likelihood of a double bit error.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a double bit error is detected, the scrubber units can be configured to halt with the current address in a scrubber register and generate an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The two scrubbers for the internal memory each have a 4-bit counter (ECNT) for the number of single bit errors corrected. This can be reset by writing 0 to it. Correctable errors do not cause an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The external scrubber unit counts both correctable and un-correctable errors it has encountered, and allows thresholds be set for each of these so that an interrupt is generated if either threshold is exceeded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;EDAC errors give rise to an interrupt on interrupt line 63 which is mapped by default to interrupt 19. A handler for this interrupt needs to be put in place by the ASW as what should be done depends on the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;if set up appropriately the EDAC system can also be used to get an indication of background radiation levels by periodically checking the number of single bit errors that have been corrected in a given time period. Again should be done, if required, by the ASW.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reporting====&lt;br /&gt;
&lt;br /&gt;
Two main types of report&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current system state, including checking for potential problems&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;System state when a problem has occurred&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Non-fatal problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Reporting the Current System State''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As all OCEOS data is readily available, and the application itself is running in kernel/supervisor mode and is able to access all registers, there is no obvious help required from OCEOS to enable an application analyse the current state of the system whenever it wishes and report on this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A different question is what conditions OCEOS itself should monitor and bring to the attention of the application so that the application can take action and perhaps prevent the emergence of a problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The standard OCEOS mechanism for bringing an anomaly to the attention of the application is to call a user defined problem handling function after updating the system state variable and making a system log entry.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
The question then becomes in what circumstances OCEOS should do this.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS will always notify the application if it detects a problem such as a task using a mutex whose ceiling is lower than the task’s priority (an application configuration error), or a task exiting while holding a mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, a deadline for the task (number of microseconds after request to start by which it should have completed) can be specified. OCEOS can automatically notify the application if a task has missed its deadline. Or alternatively, if the time when a task completed was dangerously close to its deadline.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, an expected minimum time between task start requests can be specified. OCEOS can automatically notify the application if a start request occurs sooner than this, or alternatively if the time between start requests was too close to the expected value.??&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
OCEOS can check the state of the system when it does a context switch, or when any of its directives are used, or when it performs a timed action. (Unlike many operating systems OCEOS does not depend on a regular timer tick interrupt.)&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
''Reporting System State after a problem has occurred''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the problem is non-fatal, so that OCEOS can continue, when OCEOS detects the problem it will call the user defined problem handling function after updating the system state variable and system log.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU continues to function but OCEOS cannot continue, e.g. due to an OCEOS data area being corrupted by the application, OCEOS will exit. The application can consult the OCEOS data areas and various hardware registers to determine why OCEOS had to exit. It can then restart OCEOS.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU itself must shut down, and warning is given of this before it must happen by e.g. a brown-out detector, then two reports are involved&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a short death report for use before the CPU shuts down&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a long death report put together after the system restarts&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Usually generated in an interrupt handler (e.g. brown-out detected)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The type of problem is identified by the interrupt caused&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS does not seem to have any role in reading registers, whether in EDAC or scrubber units or elsewhere, simpler to just read them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Same applies to system time if needed, just requires a timer register read.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current task and job (equivalent of thread) can be stored by OCEOS in same area as OCEOS system state variable to make both readable as one block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Other items that might be stored in this block by OCEOS include&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;system priority ceiling (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;interrupt nesting level (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on ready queue (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;current number of mutexes held (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on counting semaphore pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on data queue pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of actions on timed actions queue (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The interrupt handler might also store items in the block, e.g.&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;PC when the interrupt was called&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Stack pointer&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;EDAC/scrubber registers&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS can keep the block up to date each time a new job begins executing (not done at present but no problem). But just what should the block include??&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The block data will be preserved across resets depending on the memory used. If this is non-volatile it will be preserved across power fail/restore cycles, and accessible in creating the long death report after restart.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Don’t think OCEOS has a role in relation to the line or function where the error happened (using GCC/LLVM predefined macros, such as __LINE__)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;What other OCEOS summary information if any should kept in the quick death report data block? (The detailed information on task times etc are accessible but probably too much for the short death report.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; The application chooses the memory to be used for the OCEOS dynamic area and for the OCEOS log area. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If both of these are non-volatile a very detailed description of the state of the system when the reset occurred is available to the application after the restart and can be used by it to generate a report before it restarts OCEOS (which will overwrite the dynamic area).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the short death report block is stored in one of these areas it will also be available.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the two areas are volatile the above will still be true but only for resets that did not involve power failure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the areas are in GR716 internal memory the GR716 boot sequence needs to be taken into account. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; After a reset it is likely that register contents, whether in the CPU or elsewhere, will not have been preserved. This is true a fortiori if the reset was caused by a power failure. Critical register information, such as the PC and stack pointer, will need to be captured in the quick death report data block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Changing the default trap handler====&lt;br /&gt;
&lt;br /&gt;
The default trap handler provided by BCC may be changed by modifying trap_table_svt_tables.S provided with BCC. The default BCC trap handler __bcc_trap_table_svt_bad should be replaced with the ASW trap handler or the OCEOS default trap handler (__oceos_default_trap_handler) provided in the example applications (shown below). The application should now be recompiled and linked with the new trap_table_svt_tables.S. When application starts, all trap handlers will be in memory ready for use by the application.&lt;br /&gt;
&lt;br /&gt;
 /** &lt;br /&gt;
 * OCEOS default trap handler. &lt;br /&gt;
 */ &lt;br /&gt;
 void __oceos_default_trap_handler () &lt;br /&gt;
 { &lt;br /&gt;
   U32_t tt; &lt;br /&gt;
   __asm__ volatile ( &amp;quot;mov %%tbr, %0&amp;quot; : &amp;quot;=&amp;amp;r&amp;quot; (tt));&lt;br /&gt;
   tt = (tt &amp;amp; 0xff0) &amp;gt;&amp;gt; 4; &lt;br /&gt;
   // Log ERROR and return &lt;br /&gt;
   oceos_log_add_entry(LOG_SYSTEM_ERROR, tt); &lt;br /&gt;
   // Update System Variable &lt;br /&gt;
   U32_t current_state = oceos_system_state_get(); &lt;br /&gt;
   current_state |= STATUS_SYSTEM_ERROR; &lt;br /&gt;
   oceos_system_state_set(current_state); &lt;br /&gt;
   __asm__ volatile (&amp;quot;restore&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;jmp %l2&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;rett %l2 + 0x4&amp;quot;); &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Context Switch Logging ==&lt;br /&gt;
&lt;br /&gt;
'''Basic approach:'''&lt;br /&gt;
&lt;br /&gt;
If enabled, each time a context switch or interrupt occurs four 32-bit words are added to the context switch log.&lt;br /&gt;
&lt;br /&gt;
The first of these describes the type of switch and also gives the current window pointer (CWP) and the low 8 bits of the high 32 bits of the 64-bit system time when the switch occurred.&lt;br /&gt;
The second gives the 32-bit system time in microseconds at which the switch occurred.&lt;br /&gt;
&lt;br /&gt;
The third gives the start delay if a task is being started, otherwise a signed int giving the remaining time until the deadline or INT_MAX if the task has no deadline, a negative value gives by how much the deadline has been missed.&lt;br /&gt;
The fourth gives the current system stack pointer. &lt;br /&gt;
&lt;br /&gt;
The user specifies the number of entries in the context switch log in the application configuration. This size is given as a number in the range 3 to 12, resulting in from 2^3 to 2^12 entries. If a size outside this range is specified no context switch log is present (no header and no entries).&lt;br /&gt;
&lt;br /&gt;
If valid the size is stored in sysMetaPtr-&amp;gt;CS_log_entries_base2. If invalid this holds 0, CS logging is off.&lt;br /&gt;
&lt;br /&gt;
'''CS Log Structure:'''&lt;br /&gt;
&lt;br /&gt;
CS Header followed by circular buffer, each buffer entry four 32-bit words.&lt;br /&gt;
&lt;br /&gt;
''Switch information (first word):''&lt;br /&gt;
&lt;br /&gt;
*8 bits high time bits (31 to 24)&lt;br /&gt;
*5 bits CWP  (23 to 19)							  	      &lt;br /&gt;
*1 bit (18) switch type,  0=&amp;gt; starting, 1 =&amp;gt; interrupt or ending 				      &lt;br /&gt;
*1 bit (17) ‘from’ ID type, 0=&amp;gt; from task, 1 =&amp;gt; from interrupt				      &lt;br /&gt;
*1 bit (16) ‘to’ ID type, 0 =&amp;gt; to task, 1 =&amp;gt; to interrupt					      &lt;br /&gt;
*8 bits (15 to 8) ID of task/interrupt from which switching				      &lt;br /&gt;
*8 bits (7 to 0) ID of task/interrupt to which switching&lt;br /&gt;
 &lt;br /&gt;
:TASK_ID_INVALID (0xff) is used to indicate switching to or from the scheduler itself. 	  The interrupt ID 0 is not expected to occur, used as TO when CPU put to sleep	     Initialised by oceos_start() to 0x0000ffff (invalid as scheduler doesn’t switch to itself).&lt;br /&gt;
&lt;br /&gt;
''Context switch time word (second word):''&lt;br /&gt;
&lt;br /&gt;
:Low 32 bits of the time at which switch happened. The next 8 bits of the 64-bit system time are given in the switch information word, giving an overall 40-bit time value. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''Start wait time / deadline time margin word (third word):''&lt;br /&gt;
&lt;br /&gt;
:When first starting a task, the delay between the start request and execution beginning. Otherwise a signed int giving remaining time until deadline or 0x7fffffff if no deadline. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''System stack pointer (fourth word):''&lt;br /&gt;
&lt;br /&gt;
:System stack pointer when switch was made. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
'''Storage:'''&lt;br /&gt;
&lt;br /&gt;
Stored in log area immediately after last system log entry and before END_SENTINEL for log area.&lt;br /&gt;
&lt;br /&gt;
Space needed for CS log is included in log area size recorded at the start of the log area.&lt;br /&gt;
&lt;br /&gt;
Number of CS log entries is 2^size unless size is invalid, in which case no storage is used.&lt;br /&gt;
&lt;br /&gt;
If sysMetaPtr-&amp;gt;CS_log_entries_base2 is outside the allowed range (typically 0) no context switch logging is done. The CS header is not present, END_SENTINEL is at that position instead.&lt;br /&gt;
&lt;br /&gt;
== Recover runs ==&lt;br /&gt;
&lt;br /&gt;
The previous section describes the error diagnostic facilities provided by OCEOS. The recovery procedure is the responsibility of the application. In the worst case a system reset can be initiated by the application. The table below shows some failure modes and recommended actions to recover.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;text-align:left;&amp;quot;| SFMEA ID&lt;br /&gt;
! Failure cause&lt;br /&gt;
! Recommended action&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0010&lt;br /&gt;
|ASW sets up a non-schedulable set of tasks&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0020&lt;br /&gt;
|ASW sets up a task that may demands excessive CPU or Memory resources&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom and map file to view memory usage&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0040&lt;br /&gt;
|Human error in OCEOS code&lt;br /&gt;
|Email details to support@ocetechnology.com&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0045&lt;br /&gt;
|Divide by zero occurs in OCEOS or in ASW.&lt;br /&gt;
|ASW to implement user defined trap&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0060&lt;br /&gt;
|Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW should use EDAC scrubber to correct error and report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0070&lt;br /&gt;
|Single Event Upset, permanent (burnt bit) in RAM&lt;br /&gt;
|ASW to refactor memory location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0080&lt;br /&gt;
|Single Event Upset, temporary in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to rewrite PROM location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0090&lt;br /&gt;
|Single Event Upset, permanent (burnt-proton impact etc) in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to set indicator to boot from backup image&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0100&lt;br /&gt;
|Double bit Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW to initiate warm or cold restart&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0110&lt;br /&gt;
|RAM memory corruption by any reason e.g. incorrect write address&lt;br /&gt;
|ASW dependent but warm or cold restart are options&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.16FM-0&lt;br /&gt;
|continuous false alarm&lt;br /&gt;
|ASW to reduce alarm check interval amd mark as ignore&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0130&lt;br /&gt;
|deadlock occurs&lt;br /&gt;
|Deadlock cannot occur from OCEOS directives&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0140&lt;br /&gt;
|clock corrupted, frozen or rate drifts (HSIA crystal failure)&lt;br /&gt;
|ASW to trigger watchfod restart and report issue&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0150&lt;br /&gt;
|output before required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0160&lt;br /&gt;
|output after required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=704</id>
		<title>OCEOS Operation</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Operation&amp;diff=704"/>
		<updated>2021-10-01T12:25:31Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Building the example application */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Operations basics =&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library, header files(s), and application source files that can be compiled and linked with the standard BCC gcc or clang tools and libraries to provide a real-time multitasking application. OCEOS uses BCC library calls for some system functions. These functions are provided in the BCC board support package for the GR716. The minimum memory footprint for OCEOS is shown in the table below. Core modules occupy less than 10K bytes.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_size.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Operations manual =&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is structured as a set of managers each providing OCEOS service calls. &amp;lt;/br&amp;gt;&lt;br /&gt;
The activities supported by these managers are: &lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|''''' Initialization manager ''''':&lt;br /&gt;
|initializing the hardware and OCEOS itself&lt;br /&gt;
|-&lt;br /&gt;
|''''' Task manager ''''':&lt;br /&gt;
|handling tasks and jobs, including scheduling&lt;br /&gt;
|-&lt;br /&gt;
|''''' Interrupt manager ''''':&lt;br /&gt;
|setting up trap handlers&lt;br /&gt;
|-&lt;br /&gt;
|''''' Clock manager ''''':&lt;br /&gt;
|providing time of day, dates, and alarms&lt;br /&gt;
|-&lt;br /&gt;
|''''' Timer manager ''''':&lt;br /&gt;
|interval timing and alarms, timed outputs and jobs&lt;br /&gt;
|-&lt;br /&gt;
|''''' Mutex manager ''''':&lt;br /&gt;
|mutual exclusion management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Semaphore manager ''''':&lt;br /&gt;
|counting semaphore management&lt;br /&gt;
|-&lt;br /&gt;
|''''' Data queue manager ''''':&lt;br /&gt;
|data queue management&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The directives provided by these managers are described in the following sections.&lt;br /&gt;
&lt;br /&gt;
== Set‐up and initialisation ==&lt;br /&gt;
&lt;br /&gt;
Setup for the use of OCEOS requires the user to prepare the development environment.&lt;br /&gt;
At a minimum this requires the installation for compilers, debug tool, editors, …etc.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
=== DMON OCEOS Support===&lt;br /&gt;
:OCE added OCEOS support to DMON to help user in debugging application software. Detailed manual and available functionality can be found [[DMON_OCEOS_Support|'''here''']].&lt;br /&gt;
&lt;br /&gt;
[[File:Cpu_load_main.png|600px|Cpu Load View]] [[File:Cpu_profile_main.png|600px|Cpu Profile View]]&lt;br /&gt;
&lt;br /&gt;
=== Files provided with OCEOS ===&lt;br /&gt;
&lt;br /&gt;
Unpack the OCEOS software into an appropriate folder on the computer. The folders are as follows:&lt;br /&gt;
&lt;br /&gt;
[[File:unzip_folders.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Documentation OCEOS User Manual and Quick Reference.&lt;br /&gt;
* include Include files required by the application&lt;br /&gt;
* OCEOS_GCC_LIB oceos.a object library for applications to be built with gcc&lt;br /&gt;
* OCEOS_LLNM_LIB oceos.a object library for applications to be built with llvm (32-bit)&lt;br /&gt;
* OCEOS_LLVM_REX_LIB oceos.a object library for applications to be built with llvm (16-bit REX mode)&lt;br /&gt;
* Sample Project c sources, include files, and make files for an example project&lt;br /&gt;
* UserManualTutorials c sources, include files, and make files for User Manual tutorials and application example &lt;br /&gt;
* Excel configuration file to help produce oceos_config.h can be downloaded from [[Media:OCEOS_Config.xlsx]] &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The source and build files associated with the example application referred to in this manual are located in the folder &amp;lt;installation-folder&amp;gt; \UserManualTutorials\asw.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''asw.h''' &amp;lt;blockquote&amp;gt;Simple application header.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''asw.c''' &amp;lt;blockquote&amp;gt;Simple application example. This file is a self-contained example of an OCEOS application including tasks, mutexes, semaphores, and dataqueues.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
'''oceos_config.h''' &amp;lt;blockquote&amp;gt;This is the OCEOS application header file where the developer specifies the number of tasks, mutexes, sempahores, dataqs, log entries, and readyq entries. These numbers are used to allocate the &lt;br /&gt;
memory required for storing oceos variables. The definitions to be specified follow.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_configuration2.jpg]]&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
Notes: &amp;lt;/br&amp;gt;&lt;br /&gt;
# The application must create the number of tasks, mutexes, semaphores or dataqs specified in this header, otherwise an error will be returned from oceos_init_finish().&lt;br /&gt;
# LOG_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# FIXED_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# DYN_DATA_ARRAY_SIZE_U32S - see section OCEOS Data Areas&lt;br /&gt;
# Enumerated types are recommended for names of tasks, mutexes, semaphores and dataqs. This header file contains some examples.&lt;br /&gt;
&lt;br /&gt;
'''oceos_config.c''' &amp;lt;blockquote&amp;gt;This file contains the OCEOS data areas and the following functions:&lt;br /&gt;
# int application_init() This function initialises the oceos data area.&lt;br /&gt;
# void oceos_on_error(void* ptr) The developer should code this function to implement actions in case of a system error.&lt;br /&gt;
# void oceos_on_full_log(void* ptr)&lt;br /&gt;
The developer should code this function which is called when the system log is two-thirds full.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''makefile &amp;amp; makefile.mk''' &amp;lt;blockquote&amp;gt;These file are provided to facilitate building the asw application. Some local edits are required to point to the local compiler folders.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Building the example application ===&lt;br /&gt;
&lt;br /&gt;
Download and install the BCC2 compiler [https://www.gaisler.com/index.php/downloads/compilers from here]. &lt;br /&gt;
&lt;br /&gt;
Use the Makefile provided or use the following commands to compile and link the application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c asw.c -o asw.o&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 sparc-gaisler-elf-clang -I. -Iinclude -IC:/opt/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include -qbsp=gr716 -mcpu=leon3 -Wall -c oceos_config.c -o oceos_config.o&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 sparc-gaisler-elf-clang asw.o oceos_config.o -o asw-gr716.elf -qbsp=gr716 -mcpu=leon3 -qsvt -qnano -Wall -LC:/projects/oce/oceos/trunk/oceos_product/oceoc/build/ -loceos -Wl,-Map=asw-gr716.map&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
# sparc-gaisler-elf-clang Ensure the path to the compiler has been configured. The llvm clang compiler is recommended as the OCEOS library was compiled with it.&lt;br /&gt;
# -I. -Iinclude -I&amp;lt;bcc-install-folder&amp;gt;/bcc-2.1.1-llvm/sparc-gaisler-elf/bsp/gr716/include This -I option allows paths to include files to be passed to the compiler.&lt;br /&gt;
# -qbsp=gr716 This option specifies the compiler gr716 board support package.&lt;br /&gt;
# -mcpu=leon3 This option specifies the processor type.&lt;br /&gt;
# -Wall Display all warning messages.&lt;br /&gt;
# -c Compile only (linking not required).&lt;br /&gt;
# -o &amp;lt;filename&amp;gt; Specify the output filename.&lt;br /&gt;
# -qsvt Use the single-vector trap model described in “SPARC-V8 Supplement, SPARC-V8 Embedded (V8E) Architecture Specification”.&lt;br /&gt;
# -qnano Use a version of the newlib C library compiled for reduced foot print. The nano version implementations of the fprintf() fscanf() family of functions are not fully C standard compliant. Code size can decrease with up to # KiB when printf() is used.&lt;br /&gt;
# -L&amp;lt;path-to-oceos-library-file&amp;gt; Specify the path where liboceos.a is located.&lt;br /&gt;
# -loceos Instructs linker to use library liboceos.a&lt;br /&gt;
# -Wl,-Map=asw-gr716.map Instructs the linker to generate a map file with the name asw-gr716.map. This optional map file details the memory map of all functions and data.&lt;br /&gt;
# Consult the BCC manual for other options.&lt;br /&gt;
&lt;br /&gt;
The application executable (in this case asw.elf) can now be downloaded and executed on the target GR716 hardware. A debug tool such as DMON or GRMON is required for this. DMON provides specific support of OCEOS.&lt;br /&gt;
&lt;br /&gt;
'''''Important Note'''''&lt;br /&gt;
Up to BCC version 2.1.2 bcc_inline.h needs to be changed as it does not function on the GR716 as expected. The file is located in …\bcc-2.x.x-llvm\sparc-gaisler-elf\bsp\gr716\include\bcc\ for llvm and …\bcc-2.x.x-gcc\sparc-gaisler-elf\bsp\gr716\include\bcc for gcc.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* OCEOS comment out until BCC fix&lt;br /&gt;
 #ifdef __BCC_BSP_HAS_PWRPSR&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         uint32_t ret;&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
               &amp;quot;sll %4, %1, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;or %%o1, %2, %4\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;.word 0x83882000\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;rd %%psr, %%o1\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;andn %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;wr %4, %%o2, %%psr\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;and %%o1, %3, %%o2\n\t&amp;quot;&lt;br /&gt;
               &amp;quot;srl %%o2, %1, %0\n\t&amp;quot;&lt;br /&gt;
                 : &amp;quot;=r&amp;quot; (ret)&lt;br /&gt;
                 : &amp;quot;i&amp;quot; (PSR_PIL_BIT), &amp;quot;i&amp;quot; (PSR_ET), &amp;quot;i&amp;quot; (PSR_PIL), &amp;quot;r&amp;quot; &lt;br /&gt;
 (newpil)&lt;br /&gt;
                 : &amp;quot;o1&amp;quot;, &amp;quot;o2&amp;quot;&lt;br /&gt;
         );&lt;br /&gt;
         return ret;&lt;br /&gt;
 }&lt;br /&gt;
 #else &lt;br /&gt;
 */&lt;br /&gt;
 #include &amp;lt;bcc/leon.h&amp;gt;&lt;br /&gt;
 static inline int bcc_set_pil_inline(int newpil)&lt;br /&gt;
 {&lt;br /&gt;
         register uint32_t _val __asm__(&amp;quot;o0&amp;quot;) = newpil;&lt;br /&gt;
         /* NOTE: nop for GRLIB-TN-0018 */&lt;br /&gt;
         __asm__ volatile (&lt;br /&gt;
                 &amp;quot;ta %1\nnop\n&amp;quot; :&lt;br /&gt;
                 &amp;quot;=r&amp;quot; (_val) :&lt;br /&gt;
                 &amp;quot;i&amp;quot; (BCC_SW_TRAP_SET_PIL), &amp;quot;r&amp;quot; (_val)&lt;br /&gt;
         );&lt;br /&gt;
         return _val;&lt;br /&gt;
 } &lt;br /&gt;
 /* For OCEOS &lt;br /&gt;
 #endif&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If bcc_inline.h is not modified traps may be left disabled or in REX mode an illegal opcode trap is generated. [GRLIB]&lt;br /&gt;
&lt;br /&gt;
== Mode selection and control ==&lt;br /&gt;
&lt;br /&gt;
OCEOS is provided as an object library with header files for applications wishing to use it. There are two primary modes of operation on the GR716 as follows:&lt;br /&gt;
* SPARC V8 32-bit Mode &amp;lt;/br&amp;gt; 32-bit mode is the standard instruction word size on the SPARC V8. An OCEOS object library is provided for 32-bit mode (gcc &amp;amp; llvm)&lt;br /&gt;
* REX 16-bit mode &amp;lt;/br&amp;gt; REX mode allows the GR716 to execute 16-bit instructions. Applications running in rex mode occupy a smaller memory footprint. The compiler option -mrex should be used and -Oz for the smallest footprint.&lt;br /&gt;
&lt;br /&gt;
It is an application design choice as to which mode is used.&lt;br /&gt;
&lt;br /&gt;
== Normal operations ==&lt;br /&gt;
&lt;br /&gt;
This section describes the OCEOS directives used to in most applications. See file asw.c for example.&lt;br /&gt;
&lt;br /&gt;
The calls to get OCEOS running are:&lt;br /&gt;
&lt;br /&gt;
# application_init – uses oceoc_init to Initialise fixed data and start system time and log&lt;br /&gt;
# oceos_task_create - Create task setting priority, no of jobs, ..etc.&lt;br /&gt;
# oceos_init_finish – Initilise dynamic data area&lt;br /&gt;
# oceos_start – Start the scheduler and pass control to first task&lt;br /&gt;
&lt;br /&gt;
After steps 1 to 4 above tasks implement application functionality. If mutexes, semaphores, dataqs and/or timed actions are required they also are created at step 2. &amp;lt;/br&amp;gt;&lt;br /&gt;
Note: it is mandatory to create the number of mutexes, semaphores, and dataqs declared otherwise oceos_init_finish() will return an error.&lt;br /&gt;
&lt;br /&gt;
=== application_init() ===&lt;br /&gt;
&lt;br /&gt;
[[File:application_init.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create (…) ===&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
oceos_task_create prepares a task for execution. In the case above the parameters are:&lt;br /&gt;
* t_setup is an integer setup in the enumerated type in oceos_config.h. t_setup is used to identify this task to OCEOS thereafter. &lt;br /&gt;
[[File:enum_task_name.jpg]]&lt;br /&gt;
* 3 is the priority allocated to this task. 1 is the highest and 254 the lowest priority&lt;br /&gt;
* 3 is the priority threshold. The scheduler will only allow tasks higher than this priority to pre-empt task t_setup.&lt;br /&gt;
* 1 is the maximum number of jobs for task t_setup. 15 is the maximum number of jobs that can be ready-to-run for any task.&lt;br /&gt;
* 0 indicating that floating point is not used by this task. Enabling floating point for a task causes the scheduler to store all floating point registers on the stack when the job is pre-empted. If the job is not using floating point this causes inefficiency.&lt;br /&gt;
* 1 causes the task to be enabled on when oceos is started.&lt;br /&gt;
* setup_start is the name of the function to be executed for this task. The code for setup_start is in asw.c and the function declared in asw.h.&lt;br /&gt;
[[File:setup_start.jpg]]&lt;br /&gt;
* setup_end is the function called when task t_setup terminates.&lt;br /&gt;
[[File:setup_end.jpg]]&lt;br /&gt;
* 0 instructs the scheduler that there is no maximum execution time for this task. If a value (in microseconds) is specified the scheduer will raise an error if the task exceeds this execution time.&lt;br /&gt;
* 0 instructs the scheduler that there is no minimum time between executions of this task. If a time in microseconds is specified the scheduler will raise an error if this value is violated.&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish() ===&lt;br /&gt;
This function must be called before OCEOS is started. It completes the initialisation of OCEOS data for the application.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_init_finish.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_start() ===&lt;br /&gt;
&lt;br /&gt;
This function starts task scheduling in OCEOS. It should never return from this function.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters passed to oceos_start are:&lt;br /&gt;
* fixed_data is a pointer to the start of the fixed data area. It is declared in oceos_config.c.&lt;br /&gt;
* t_setup is the ID of the task to be set executing when OCEOS starts (in oceos_config.h).&lt;br /&gt;
* Optional pointer that will be passed to the task started, here t_setup.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive starts an instance of a task, called a job in OCEOS. In this case start means puts an instance of the task, a job, on the ready-to-run queue, and performs a reschedule.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; If it is the highest priority job ready-to-run, it will be set running by the scheduler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_start.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The parameters passed to it are the task ID and a pointer. It returns an integer indicating the status of the call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many cases the first task to be run by OCEOS will perform application initialisation and then start the other application tasks including the idle task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex. It must be called before oceos_init_finish(). Parameters passed are the mutex ID and the priority ceiling for the mutex.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling is the priority of the highest task that uses the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note that the user must determine this priority ceiling as part of the application design. &lt;br /&gt;
OCEOS relies on the developer to specify the correct priority ceiling.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_create.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive assigns the mutex to the calling job. It should always be successful because a job should only be set running if the mutex is available to it.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_wait.jpg]]&lt;br /&gt;
&lt;br /&gt;
The mutex ID is the only parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive releases a mutex from a job. It will cause a reschedule and if a higher priority job has been waiting on the mutex it will start causing this job to be pre-empted.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_mutex_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The only parameter to the directive is the mutex ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a counting semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_create2.jpg |700px]]&lt;br /&gt;
&lt;br /&gt;
* Semaphore ID (0 to 62)&lt;br /&gt;
* Maximum No of permits (1 to 4094)&lt;br /&gt;
* Starting number of permits (1 to 4094)&lt;br /&gt;
* Maximum number of jobs on this semaphore queue (1 to 254)&lt;br /&gt;
* Whether timeout is used in oceos_sem_wait_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameter is:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout (..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the semaphore and the job continues if the semaphore is greater then zero. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the semaphore is equal to zero then the job is put on a queue until the semaphore is incremented (signalled), at which time the job is restarted.&lt;br /&gt;
If a timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Note that the job is restarted from scratch and not just continued from the directive call.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_sem_wait_restart_timeout.jpg]]&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* Sempahore ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer, long long)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive increments (signals) the specified semaphore.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_sem_signal.jpg]]&lt;br /&gt;
&lt;br /&gt;
The semaphore ID is the sole parameter.&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create (..) ===&lt;br /&gt;
&lt;br /&gt;
This directive creates a data queue with specified ID&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_create2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Data Queue Size (1 to 255)&lt;br /&gt;
* Data Queue maximum number of pending jobs (1 to 255)&lt;br /&gt;
* Data Queue roll-overs enable/disable (0 or 1)&lt;br /&gt;
* Whether timeout is used in oceos_dataq_read_restart_timeout&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout(..) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive reads a pointer from the specified data queue. If the data queue is empty the task is put on a queue to be restarted when a new pointer has been added to the queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A timeout in microseconds can be set, after which the task will not be restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Oceos_dataq_read_restart_timeout2.jpg]]&lt;br /&gt;
&lt;br /&gt;
* Data Queue ID (0 to 62)&lt;br /&gt;
* Timeout in microseconds (64-bit integer)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write(..) ===&lt;br /&gt;
&lt;br /&gt;
This directive puts a pointer on the specified data queue.&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_dataq_write.jpg]]&lt;br /&gt;
&lt;br /&gt;
Parameters are :&lt;br /&gt;
* Data queue ID (0 to 62)&lt;br /&gt;
* Pointer to be put on queue (void *ptr)&lt;br /&gt;
&lt;br /&gt;
== Normal termination ==&lt;br /&gt;
&lt;br /&gt;
It is not normal for OCEOS to terminate. Application tasks usually continue to execute without stopping. If all tasks terminate the system goes to sleep mode and only an interrupt can restart activity.&lt;br /&gt;
&lt;br /&gt;
== Error conditions ==&lt;br /&gt;
&lt;br /&gt;
Error conditions are handled in 4 different ways by OCEOS as follows:&lt;br /&gt;
* Directive return codes allowing application take appropriate action&lt;br /&gt;
* The System Log keeps a record of problems and when they occurred&lt;br /&gt;
* The System State variable indicates the current state of OCEOS&lt;br /&gt;
* The watchdog provides a fallback reset in unpredictable situations&lt;br /&gt;
&lt;br /&gt;
=== Directive return codes ===&lt;br /&gt;
&lt;br /&gt;
OCEOS is driven by directives described in the Reference section below. All directives return a status to be checked by the application. The directive return status is either success or a code indicating why it failed. The table below is taken from oceos.h. It is the responsibility of the application to take appropriate action if a directive call fails.&lt;br /&gt;
&lt;br /&gt;
[[File:Enum_directive_status2.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== The System Log ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;When a problem arises, either in application code or in OCEOS itself, it is useful to have a record of &amp;lt;/p&amp;gt;&lt;br /&gt;
# '''when''' it happened&lt;br /&gt;
# '''what''' kind of problem it was&lt;br /&gt;
# '''where''' it happened.&lt;br /&gt;
&amp;lt;p&amp;gt;The primary purpose of the System Log is to provide this ‘when’, ‘what’, and ‘where’ information.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It does so as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''when''':   the low 32-bits of the system time are automatically recorded when a log entry is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''what''':   an 8-bit number allows 256 different types of entry be specified. Half of these entry types (0x80 to 0xff) are reserved for internal us in OCEOS. The other 128 entry types (0 to 0x7f) are assigned their meanings by the application. (An OCEOS internal code reserved for that purpose is used if an application attempts to use an OCEOS internal code.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;'''where''':  a 24-bit number is included in each log entry. OCEOS itself uses this to indicate the OCEOS function where the log entry call was made and other information. Application code can use this number in whatever way is appropriate for the application.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The log is located in the log area. This area starts at an address specified by the application developer, begins with a 32-bit constant sentinel value followed by a 32-bit count of the number of 32-bit words making up the area (including the sentinels) and ends with a 32-bit constant sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As frequent access to the log area is not likely to be needed the log area can be located in memory external to the GR716. The log area contents will then usually be preserved across system resets, and across system power on/off cycles if the external memory is non-volatile.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The log is structured as a circular buffer, with its read and write indices also stored in the log area. It is set up initially by oceos_init(). This does not overwrite the data currently in the log but resets the read and write indices to be equal and as far as can be determined after the most recent log entry. As the log indices are equal the log now appears empty when an attempt to read it in the usual way is made, but a special directive allows the application program read the data at any position in the log. Another directive allows the application reset all log entries.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Any system that uses OCEOS must have a system log. The number of entries in the log is specified in the system configuration structure, and must be within the specified range or 0, in which case a default value is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The header file oceos.h gives the structure of the log area and the values of the associated constants.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 struct log_entry{&lt;br /&gt;
  U32_t time32;&lt;br /&gt;
  unsigned int entry_type :8;&lt;br /&gt;
  unsigned int entry_comment :24;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
 * Log entry types used when creating a log entry (8 bits, from 0 to 255 only)&lt;br /&gt;
 */&lt;br /&gt;
 enum LOG_ENTRY_TYPE{&lt;br /&gt;
  LOG_SYS_OK = 0x80U,&lt;br /&gt;
  LOG_NULL_FATAL,&lt;br /&gt;
  LOG_OCEOS_ABORT,&lt;br /&gt;
  LOG_INVALID_SYSTEM_STATE,&lt;br /&gt;
  LOG_LOG_NOT_VALID_ENTRY,&lt;br /&gt;
  LOG_STATUS_INVALID,&lt;br /&gt;
  LOG_NULL_POINTER,&lt;br /&gt;
  LOG_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_INIT_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_FREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_CONFIG_UNFREEZE_FAIL,&lt;br /&gt;
  LOG_TIME_RESET_FAIL,&lt;br /&gt;
  LOG_TIME_SCALER_FAIL,&lt;br /&gt;
  LOG_TIME_RELOAD_FAIL,&lt;br /&gt;
  LOG_TIME_COUNTER_FAIL,&lt;br /&gt;
  LOG_TIME_CONTROL_FAIL,&lt;br /&gt;
  LOG_TIME_POINTER_NULL,&lt;br /&gt;
  LOG_TIME_POINTER_LOW_NULL,&lt;br /&gt;
  LOG_TIME_START_FAIL,&lt;br /&gt;
  LOG_FIXED_INIT_FAIL,&lt;br /&gt;
  LOG_DYNAMIC_INIT_FAIL,&lt;br /&gt;
  LOG_INIT_TASK_START_FAIL,&lt;br /&gt;
  LOG_DEADLINE_MISSED,&lt;br /&gt;
  LOG_TASK_DISABLED,&lt;br /&gt;
  LOG_TASK_ENABLED,&lt;br /&gt;
  LOG_JOB_INVALID,&lt;br /&gt;
  LOG_JOB_NONE_FREE,&lt;br /&gt;
  LOG_JOB_NOT_EXECUTING,&lt;br /&gt;
  LOG_JOB_NOT_ACTIVE,&lt;br /&gt;
  LOG_READYQ_TOO_BIG,&lt;br /&gt;
  LOG_READYQ_SENTINEL_BAD,&lt;br /&gt;
  LOG_READYQ_FULL,&lt;br /&gt;
  LOG_READYQ_EMPTY,&lt;br /&gt;
  LOG_READYQ_PUT_DISABLED_TASK,&lt;br /&gt;
  LOG_READYQ_PUT_FAIL,&lt;br /&gt;
  LOG_READYQ_REMOVE_DONE,&lt;br /&gt;
  LOG_READYQ_REMOVE_FAIL,&lt;br /&gt;
  LOG_PARAM_BAD_ID,&lt;br /&gt;
  LOG_PARAM_BAD_TIME,&lt;br /&gt;
  LOG_PARAM_ACTION_MISSING,&lt;br /&gt;
  LOG_PARAM_JOB_MISSING,&lt;br /&gt;
  LOG_MUTEX_BAD_CEILING,&lt;br /&gt;
  LOG_MUTEX_ALREADY_HELD,&lt;br /&gt;
  LOG_MUTEX_ALREADY_FREE,&lt;br /&gt;
  LOG_MUTEX_WRONG_JOB,&lt;br /&gt;
  LOG_MUTEX_NESTING_BAD,&lt;br /&gt;
  LOG_MUTEX_EXIT_HOLDING,&lt;br /&gt;
  LOG_SEMAPHORE_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_SEMAPHORE_MAX_ALREADY_REACHED,&lt;br /&gt;
  LOG_SEMAPHORE_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_PENDING_TIMED_REMOVE_FAIL,&lt;br /&gt;
  LOG_SEMAPHORE_TRANSFER_READYQ_FAIL,&lt;br /&gt;
  LOG_DATAQ_FULL,&lt;br /&gt;
  LOG_DATAQ_EMPTY,&lt;br /&gt;
  LOG_DATAQ_COUNT_EXCEEDED,&lt;br /&gt;
  LOG_DATAQ_PENDING_QUEUE_FULL,&lt;br /&gt;
  LOG_DATAQ_INVALID_PENDING_JOB,&lt;br /&gt;
  LOG_DATAQ_PENDING_REMOVE_FAIL,&lt;br /&gt;
  LOG_DATAQ_TIMED_JOB_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_NULL,&lt;br /&gt;
  LOG_TIMED_ACTION_TIMER_STOP_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_NOT_INIT,&lt;br /&gt;
  LOG_TIMED_ACTION_INT_REG_FAILED,&lt;br /&gt;
  LOG_TIMED_ACTION_INVALID,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_INDEX,&lt;br /&gt;
  LOG_TIMED_ACTION_MISSED,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_FULL,&lt;br /&gt;
  LOG_TIMED_ACTION_Q_EMPTY,&lt;br /&gt;
  LOG_TIMED_ACTION_PUT_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_REMOVE_FAIL,&lt;br /&gt;
  LOG_TIMED_ACTION_BAD_JOB_ID,&lt;br /&gt;
  LOG_TIMED_ACTION_DO_FAIL,&lt;br /&gt;
  LOG_SYSTEM_ERROR,&lt;br /&gt;
  LOG_TIME_BSP_SYSFREQ_NULL,&lt;br /&gt;
  LOG_SEMAPHORE_TIMEOUT_NOT_INIT,  &lt;br /&gt;
  LOG_DATAQ_TIMEOUT_NOT_INIT, &lt;br /&gt;
  LOG_TIMED_ACTION_START_WHILE_RUNNING,&lt;br /&gt;
  LOG_INT_HANDLER_IS_NULL,&lt;br /&gt;
  LOG_SET_OCEOS_TRAP_HANDLER_FAILED,&lt;br /&gt;
  LOG_INT_CALLED_NO_INIT,&lt;br /&gt;
  LOG_FAILED_SET_INT_PRIO,  &lt;br /&gt;
  LOG_FAILED_PENDSV_INIT,&lt;br /&gt;
  LOG_SYS_TIME_NOT_INIT    &lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_add_entry(&lt;br /&gt;
 enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
 const unsigned int // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_remove_entry(struct log_entry * const);&lt;br /&gt;
 &lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_get_indexed_entry(&lt;br /&gt;
 const unsigned int,&lt;br /&gt;
 struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
=== The System State variable ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/p&amp;gt;OCEOS maintains a system state variable which shows the current state of the system. States are shown below. If the system state deviates from normal (value 0) the user defined function oceos_on_error(..) is called by OCEOS. The source code for this function is located config.c and should be written by the application developer to take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directives oceos_system_state_get and oceos_system_state_set are provided to allow the application to access the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 void oceos_on_error(void* ptr) { // Application dependent error handling code should be included here&lt;br /&gt;
 return;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
 * The 32-bit system state variable indicates the current system state&lt;br /&gt;
 */&lt;br /&gt;
 #define STATUS_NORMAL 0u // System State Normal&lt;br /&gt;
 #define STATUS_EDAC_INTERNAL 1u // Uncorrectable error in internal memory&lt;br /&gt;
 #define STATUS_EDAC_EXTERNAL 2u // Uncorrectable error in external memory&lt;br /&gt;
 #define STATUS_MEM_PROT_1 4u // Invalid access memory protection unit 1&lt;br /&gt;
 #define STATUS_MEM_PROT_2 8u // Invalid access memory protection unit 2&lt;br /&gt;
 #define STATUS_DISABLED_TASK_START 0x10u // An attempt to start a disabled task&lt;br /&gt;
 #define STATUS_TASK_JOB_LIMIT_OVER 0x20u // An attempt to execute a task when its jobs limit is already reached.&lt;br /&gt;
 #define STATUS_JOB_OVER_TIME 0x40u // Job time from creation to completion exceeds allowed maximum for a task.&lt;br /&gt;
 #define STATUS_JOB_INTERVAL_SHORT 0x80u // Minimum time between job creations is less than the allowed minimum for task&lt;br /&gt;
 #define STATUS_READYQ_FULL 0x100u // Ready queue unable to accept job as result of being full&lt;br /&gt;
 #define STATUS_MUTEX_ALREADY_HELD 0x200u // Mutex wait() when mutex already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_HELD 0x400u // Mutex signal() when not already held&lt;br /&gt;
 #define STATUS_MUTEX_NOT_RETURNED 0x800u // Mutex not returned before job terminates&lt;br /&gt;
 #define STATUS_SEMAPHORE_JOBS_FULL 0x1000u // Attempt to add job to semaphore pending list when list full&lt;br /&gt;
 #define STATUS_DATAQ_FULL 0x2000u // Data queue write when queue already full&lt;br /&gt;
 #define STATUS_DATAQ_JOBS_FULL 0x4000u // Attempt to add job to queue pending list when list full&lt;br /&gt;
 #define STATUS_TIMED_JOBS_FULL 0x8000u // Timed jobs queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_JOB_LATE 0x10000u // Timed jobs queue late job transfer to scheduler&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_FULL 0x20000u // Timed output queue write when queue already full&lt;br /&gt;
 #define STATUS_TIMED_OUTPUT_LATE 0x40000u // Timed output late&lt;br /&gt;
 #define STATUS_BAD_LOG 0x80000000u // System Log corruption&lt;br /&gt;
 #define STATUS_INVALID 0xffffffffu // Invalid system state&lt;br /&gt;
&lt;br /&gt;
=== The watchdog ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 provides watchdog functionality (ref: GR716 Advanced Data Sheet and User’s Manual). OCEOS provides functions to allow applications to use this watchdog functionality (see section 10 for more details). It is expected that OCEOS applications using the watchdog have a low priority task to continually reset the watchdog timer using the directive oceos_system_watchdog_reset(..). If the watchdog reaches its timeout value this is an indication that a severe error has occurred and a hardware reset is generated by the watchdog unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application when rebooted can optionally check the system log, and last system state to determine the cause of the watchdog reboot and take appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Hardware errors ===&lt;br /&gt;
&lt;br /&gt;
Hardware errors can come from a number of sources including the following:&lt;br /&gt;
* Uncorrectable memory errors&lt;br /&gt;
* Memory protection violations&lt;br /&gt;
* Brown-out or low power&lt;br /&gt;
The OCEOS philosophy to dealing with these and other hardware faults causing interrupts is to provide directives enabling the application to take appropriate actions. OCEOS directives available for application recovery are:&lt;br /&gt;
* oceos_interrupt_handle_register This directive may be used to setup application recovery interrupt service routines.&lt;br /&gt;
* oceos_exit This directive may be called to exit OCEOS back to the application for appropriate recovery actions.&lt;br /&gt;
* oceos_log_get_indexed_entry This directive may be used as part of the application fault analysis.&lt;br /&gt;
* oceos_system_state_get This action allows the application obtain the system status to determine appropriate recovery action.&lt;br /&gt;
&lt;br /&gt;
=== Overload and system failure ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overloads and system failure are different but have some common features. Both can lead to an unexpected system restart, and to the question ‘what caused that?’. Both can sometimes be anticipated if warning signs are noticed. It may even be possible to avoid them by taking appropriate action.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Some thoughts and suggestions about them and OCEOS follow below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Overload ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Overload generally refers to insufficient CPU time to handle a situation.&lt;br /&gt;
Can also be a memory shortage, for example insufficient stack space.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;A task missing a soft deadline - needs to be noted&amp;lt;/li&amp;gt; &lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;A task missing a hard deadline - may be catastrophic&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Watchdog timeout - hardware reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inability to start a task due to memory shortage&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Interrupts more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task pre-empted more often than expected causing task completion to be delayed&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Tasks start requests more frequent than expected&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Inappropriate allocation of task priorities&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;One or more tasks using more than the expected CPU time (should not happen)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Holding one or more mutexes for too long&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Using mutexes in a non-nested manner&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Insufficient stack space&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;(With OCEOS unbounded priority inversion cannot occur.)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;(With OCEOS chained blocking cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;(With OCEOS deadlocks cannot occur)&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Information available for comparison to expected values to detect potential overload'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Task maximum duration – job creation time to termination time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Task maximum CPU time&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Task minimum time between start requests&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Task number of times pre-empted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Task maximum current jobs for a task&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Watchdog timer nearly timed out when reset&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Stack pointer approaching limit of allowed range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Et alia&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Disable certain interrupts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Disable a task or tasks&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Kill currently executing job&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== System failure ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;System failure generally refers to the CPU ceasing to execute instructions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Can also be a reference to the operating system (OCEOS) having to exit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Usually associated with hardware problems, but software can do it too.&amp;lt;/p&amp;gt;&lt;br /&gt;
''Results in'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;OCEOS exit (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;CPU stops execution (in some cases)&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;A subsequent restart (hopefully)&amp;lt;/li&amp;gt;&lt;br /&gt;
''Typical causes'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Critical OCEOS data corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Un-correctable memory error&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Memory hardware failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Power failure&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Environment more demanding than design anticipated causing hardware problems&amp;lt;/li&amp;gt;&lt;br /&gt;
''Warning signs that can indicate something wrong at system level'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Sentinels on OCEOS critical data areas corrupted&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Stack pointer approaching limit of range&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Corrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Uncorrected memory error counts&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Voltage levels - brown out detection interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
''Run time avoidance actions'':&lt;br /&gt;
# &amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Use EDAC scrubber units to continually regenerate all RAM&amp;lt;/li&amp;gt;&lt;br /&gt;
# &amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Use MEMPROT unit to restrict OCEOS fixed data write access to the scrubber only&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Current System State ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Before discussing reports it seems appropriate to describe how the system state is stored and accessed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - OCEOS and the Application software'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For OCEOS this is given by its fixed data area, its dynamic data area, and its log data area. Also by some heap items and the stack and registers, including the PC. The latter are also relevant to the application state.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The locations and sizes of three OCEOS areas are determined by the application. Their lay-outs are known. A meta-data structure in the fixed area provides pointers to the principal fields within each data area and simplifies access by OCEOS and by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The three OCEOS areas are available for inspection after OCEOS exits and before it restarts as well as while it is running. This helps after a restart in assessing what went wrong, as well as allowing an application check for lurking problems while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(OCEOS does not allow tasks etc. be created once scheduling has begun, and as a result does not need to use dynamic memory allocation. The memory areas it uses can thus be fixed in advance, their locations and sizes determined by the application.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The task information items mentioned above are automatically updated by OCEOS in the dynamic data area and can be accessed by the application at any time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system state variable contains flags that indicate a certain problem has occurred. It is automatically updated by OCEOS using ‘OR’ to avoiding losing information, typically a user defined function is called to deal with the problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two sets of flags are kept as part of the system state variable. One accumulates indicators of all problems that have occurred, and typically is reset by the application only after a restart. The other indicates current problems, and typically is reset by the user defined problem handling function.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The OCEOS system log records when, what, and in some cases where something occurred. It is automatically written to by OCEOS in certain conditions and can also be read and written by the application. (Codes for what from 0x80 to 0xff are reserved for use by OCEOS, codes 0 to 0x7f are available for use by the application. At present only 24 bits are used to indicate where, this can be expanded to e.g. include the PC or stack pointer.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;At present the log area contains the system state variable as well as the system log. The system state variable could equally well be stored in the dynamic data area.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Current System State - Hardware'':&lt;br /&gt;
&lt;br /&gt;
Registers&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 has 504 32-bit IU registers, organized in 31 windows. In addition there are the usual processor registers PC, SP, Y, %psr, %wim and %tbr, and ancillary state registers %asr16, %asr17, %asr20, %asr22-23, %asr24-31. There are also 32 floating point registers, each 32-bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Other units with registers that have a key role in determining the current hardware state include the interrupt controller, the clock gating units, the EDAC and memory scrubber units, and the statistics unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;After a reset registers may have been automatically reset to some initial value and their previous content lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
EDAC&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The internal data and instruction RAMs and the external RAM have individual EDAC and scrubber units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Normally the scrubber units will be configured to cycle through the memory, reading each location and writing it back if an error is detected, thus helping reduce the likelihood of a double bit error.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a double bit error is detected, the scrubber units can be configured to halt with the current address in a scrubber register and generate an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The two scrubbers for the internal memory each have a 4-bit counter (ECNT) for the number of single bit errors corrected. This can be reset by writing 0 to it. Correctable errors do not cause an interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The external scrubber unit counts both correctable and un-correctable errors it has encountered, and allows thresholds be set for each of these so that an interrupt is generated if either threshold is exceeded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;EDAC errors give rise to an interrupt on interrupt line 63 which is mapped by default to interrupt 19. A handler for this interrupt needs to be put in place by the ASW as what should be done depends on the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;if set up appropriately the EDAC system can also be used to get an indication of background radiation levels by periodically checking the number of single bit errors that have been corrected in a given time period. Again should be done, if required, by the ASW.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Reporting====&lt;br /&gt;
&lt;br /&gt;
Two main types of report&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current system state, including checking for potential problems&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;System state when a problem has occurred&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Non-fatal problem&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Reporting the Current System State''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As all OCEOS data is readily available, and the application itself is running in kernel/supervisor mode and is able to access all registers, there is no obvious help required from OCEOS to enable an application analyse the current state of the system whenever it wishes and report on this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A different question is what conditions OCEOS itself should monitor and bring to the attention of the application so that the application can take action and perhaps prevent the emergence of a problem.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The standard OCEOS mechanism for bringing an anomaly to the attention of the application is to call a user defined problem handling function after updating the system state variable and making a system log entry.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
The question then becomes in what circumstances OCEOS should do this.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS will always notify the application if it detects a problem such as a task using a mutex whose ceiling is lower than the task’s priority (an application configuration error), or a task exiting while holding a mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, a deadline for the task (number of microseconds after request to start by which it should have completed) can be specified. OCEOS can automatically notify the application if a task has missed its deadline. Or alternatively, if the time when a task completed was dangerously close to its deadline.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a task is created, an expected minimum time between task start requests can be specified. OCEOS can automatically notify the application if a start request occurs sooner than this, or alternatively if the time between start requests was too close to the expected value.??&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
OCEOS can check the state of the system when it does a context switch, or when any of its directives are used, or when it performs a timed action. (Unlike many operating systems OCEOS does not depend on a regular timer tick interrupt.)&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
''Reporting System State after a problem has occurred''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the problem is non-fatal, so that OCEOS can continue, when OCEOS detects the problem it will call the user defined problem handling function after updating the system state variable and system log.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU continues to function but OCEOS cannot continue, e.g. due to an OCEOS data area being corrupted by the application, OCEOS will exit. The application can consult the OCEOS data areas and various hardware registers to determine why OCEOS had to exit. It can then restart OCEOS.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If the CPU itself must shut down, and warning is given of this before it must happen by e.g. a brown-out detector, then two reports are involved&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a short death report for use before the CPU shuts down&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;a long death report put together after the system restarts&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Short death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Usually generated in an interrupt handler (e.g. brown-out detected)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The type of problem is identified by the interrupt caused&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS does not seem to have any role in reading registers, whether in EDAC or scrubber units or elsewhere, simpler to just read them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Same applies to system time if needed, just requires a timer register read.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Current task and job (equivalent of thread) can be stored by OCEOS in same area as OCEOS system state variable to make both readable as one block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Other items that might be stored in this block by OCEOS include&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;system priority ceiling (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;interrupt nesting level (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on ready queue (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;current number of mutexes held (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on counting semaphore pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of jobs on data queue pending queues (2 bytes)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;number of actions on timed actions queue (1 byte)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The interrupt handler might also store items in the block, e.g.&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;PC when the interrupt was called&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Stack pointer&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;EDAC/scrubber registers&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;OCEOS can keep the block up to date each time a new job begins executing (not done at present but no problem). But just what should the block include??&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The block data will be preserved across resets depending on the memory used. If this is non-volatile it will be preserved across power fail/restore cycles, and accessible in creating the long death report after restart.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Don’t think OCEOS has a role in relation to the line or function where the error happened (using GCC/LLVM predefined macros, such as __LINE__)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;What other OCEOS summary information if any should kept in the quick death report data block? (The detailed information on task times etc are accessible but probably too much for the short death report.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Long death report: Comments&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; The application chooses the memory to be used for the OCEOS dynamic area and for the OCEOS log area. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If both of these are non-volatile a very detailed description of the state of the system when the reset occurred is available to the application after the restart and can be used by it to generate a report before it restarts OCEOS (which will overwrite the dynamic area).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the short death report block is stored in one of these areas it will also be available.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the two areas are volatile the above will still be true but only for resets that did not involve power failure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; If the areas are in GR716 internal memory the GR716 boot sequence needs to be taken into account. &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; After a reset it is likely that register contents, whether in the CPU or elsewhere, will not have been preserved. This is true a fortiori if the reset was caused by a power failure. Critical register information, such as the PC and stack pointer, will need to be captured in the quick death report data block.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Changing the default trap handler====&lt;br /&gt;
&lt;br /&gt;
The default trap handler provided by BCC may be changed by modifying trap_table_svt_tables.S provided with BCC. The default BCC trap handler __bcc_trap_table_svt_bad should be replaced with the ASW trap handler or the OCEOS default trap handler (__oceos_default_trap_handler) provided in the example applications (shown below). The application should now be recompiled and linked with the new trap_table_svt_tables.S. When application starts, all trap handlers will be in memory ready for use by the application.&lt;br /&gt;
&lt;br /&gt;
 /** &lt;br /&gt;
 * OCEOS default trap handler. &lt;br /&gt;
 */ &lt;br /&gt;
 void __oceos_default_trap_handler () &lt;br /&gt;
 { &lt;br /&gt;
   U32_t tt; &lt;br /&gt;
   __asm__ volatile ( &amp;quot;mov %%tbr, %0&amp;quot; : &amp;quot;=&amp;amp;r&amp;quot; (tt));&lt;br /&gt;
   tt = (tt &amp;amp; 0xff0) &amp;gt;&amp;gt; 4; &lt;br /&gt;
   // Log ERROR and return &lt;br /&gt;
   oceos_log_add_entry(LOG_SYSTEM_ERROR, tt); &lt;br /&gt;
   // Update System Variable &lt;br /&gt;
   U32_t current_state = oceos_system_state_get(); &lt;br /&gt;
   current_state |= STATUS_SYSTEM_ERROR; &lt;br /&gt;
   oceos_system_state_set(current_state); &lt;br /&gt;
   __asm__ volatile (&amp;quot;restore&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;jmp %l2&amp;quot;); &lt;br /&gt;
   __asm__ volatile (&amp;quot;rett %l2 + 0x4&amp;quot;); &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Context Switch Logging ==&lt;br /&gt;
&lt;br /&gt;
'''Basic approach:'''&lt;br /&gt;
&lt;br /&gt;
If enabled, each time a context switch or interrupt occurs four 32-bit words are added to the context switch log.&lt;br /&gt;
&lt;br /&gt;
The first of these describes the type of switch and also gives the current window pointer (CWP) and the low 8 bits of the high 32 bits of the 64-bit system time when the switch occurred.&lt;br /&gt;
The second gives the 32-bit system time in microseconds at which the switch occurred.&lt;br /&gt;
&lt;br /&gt;
The third gives the start delay if a task is being started, otherwise a signed int giving the remaining time until the deadline or INT_MAX if the task has no deadline, a negative value gives by how much the deadline has been missed.&lt;br /&gt;
The fourth gives the current system stack pointer. &lt;br /&gt;
&lt;br /&gt;
The user specifies the number of entries in the context switch log in the application configuration. This size is given as a number in the range 3 to 12, resulting in from 2^3 to 2^12 entries. If a size outside this range is specified no context switch log is present (no header and no entries).&lt;br /&gt;
&lt;br /&gt;
If valid the size is stored in sysMetaPtr-&amp;gt;CS_log_entries_base2. If invalid this holds 0, CS logging is off.&lt;br /&gt;
&lt;br /&gt;
'''CS Log Structure:'''&lt;br /&gt;
&lt;br /&gt;
CS Header followed by circular buffer, each buffer entry four 32-bit words.&lt;br /&gt;
&lt;br /&gt;
''Switch information (first word):''&lt;br /&gt;
&lt;br /&gt;
*8 bits high time bits (31 to 24)&lt;br /&gt;
*5 bits CWP  (23 to 19)							  	      &lt;br /&gt;
*1 bit (18) switch type,  0=&amp;gt; starting, 1 =&amp;gt; interrupt or ending 				      &lt;br /&gt;
*1 bit (17) ‘from’ ID type, 0=&amp;gt; from task, 1 =&amp;gt; from interrupt				      &lt;br /&gt;
*1 bit (16) ‘to’ ID type, 0 =&amp;gt; to task, 1 =&amp;gt; to interrupt					      &lt;br /&gt;
*8 bits (15 to 8) ID of task/interrupt from which switching				      &lt;br /&gt;
*8 bits (7 to 0) ID of task/interrupt to which switching&lt;br /&gt;
 &lt;br /&gt;
:TASK_ID_INVALID (0xff) is used to indicate switching to or from the scheduler itself. 	  The interrupt ID 0 is not expected to occur, used as TO when CPU put to sleep	     Initialised by oceos_start() to 0x0000ffff (invalid as scheduler doesn’t switch to itself).&lt;br /&gt;
&lt;br /&gt;
''Context switch time word (second word):''&lt;br /&gt;
&lt;br /&gt;
:Low 32 bits of the time at which switch happened. The next 8 bits of the 64-bit system time are given in the switch information word, giving an overall 40-bit time value. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''Start wait time / deadline time margin word (third word):''&lt;br /&gt;
&lt;br /&gt;
:When first starting a task, the delay between the start request and execution beginning. Otherwise a signed int giving remaining time until deadline or 0x7fffffff if no deadline. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
''System stack pointer (fourth word):''&lt;br /&gt;
&lt;br /&gt;
:System stack pointer when switch was made. Initialised to 0.&lt;br /&gt;
&lt;br /&gt;
'''Storage:'''&lt;br /&gt;
&lt;br /&gt;
Stored in log area immediately after last system log entry and before END_SENTINEL for log area.&lt;br /&gt;
&lt;br /&gt;
Space needed for CS log is included in log area size recorded at the start of the log area.&lt;br /&gt;
&lt;br /&gt;
Number of CS log entries is 2^size unless size is invalid, in which case no storage is used.&lt;br /&gt;
&lt;br /&gt;
If sysMetaPtr-&amp;gt;CS_log_entries_base2 is outside the allowed range (typically 0) no context switch logging is done. The CS header is not present, END_SENTINEL is at that position instead.&lt;br /&gt;
&lt;br /&gt;
== Recover runs ==&lt;br /&gt;
&lt;br /&gt;
The previous section describes the error diagnostic facilities provided by OCEOS. The recovery procedure is the responsibility of the application. In the worst case a system reset can be initiated by the application. The table below shows some failure modes and recommended actions to recover.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! style=&amp;quot;text-align:left;&amp;quot;| SFMEA ID&lt;br /&gt;
! Failure cause&lt;br /&gt;
! Recommended action&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0010&lt;br /&gt;
|ASW sets up a non-schedulable set of tasks&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0020&lt;br /&gt;
|ASW sets up a task that may demands excessive CPU or Memory resources&lt;br /&gt;
|ASW uses oceos_task_get_info to determine schedulability headroom and map file to view memory usage&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0040&lt;br /&gt;
|Human error in OCEOS code&lt;br /&gt;
|Email details to support@ocetechnology.com&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0045&lt;br /&gt;
|Divide by zero occurs in OCEOS or in ASW.&lt;br /&gt;
|ASW to implement user defined trap&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0060&lt;br /&gt;
|Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW should use EDAC scrubber to correct error and report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0070&lt;br /&gt;
|Single Event Upset, permanent (burnt bit) in RAM&lt;br /&gt;
|ASW to refactor memory location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0080&lt;br /&gt;
|Single Event Upset, temporary in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to rewrite PROM location and report error&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0090&lt;br /&gt;
|Single Event Upset, permanent (burnt-proton impact etc) in PROM housing master image of OCEOS for initialisation&lt;br /&gt;
|ASW to set indicator to boot from backup image&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0100&lt;br /&gt;
|Double bit Single Event Upset, temporary in RAM&lt;br /&gt;
|ASW to initiate warm or cold restart&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0110&lt;br /&gt;
|RAM memory corruption by any reason e.g. incorrect write address&lt;br /&gt;
|ASW dependent but warm or cold restart are options&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.16FM-0&lt;br /&gt;
|continuous false alarm&lt;br /&gt;
|ASW to reduce alarm check interval amd mark as ignore&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0130&lt;br /&gt;
|deadlock occurs&lt;br /&gt;
|Deadlock cannot occur from OCEOS directives&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0140&lt;br /&gt;
|clock corrupted, frozen or rate drifts (HSIA crystal failure)&lt;br /&gt;
|ASW to trigger watchfod restart and report issue&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0150&lt;br /&gt;
|output before required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|-&lt;br /&gt;
|SFMEA-4.4.1.FM-0160&lt;br /&gt;
|output after required time&lt;br /&gt;
|ASW to report log&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=703</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=703"/>
		<updated>2021-10-01T11:22:52Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Error messages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=702</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=702"/>
		<updated>2021-10-01T11:01:10Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Two-phase build to miminise memory used */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=701</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=701"/>
		<updated>2021-10-01T10:54:16Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Further Design Details */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=700</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=700"/>
		<updated>2021-10-01T10:40:32Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* FDIR Manager directives */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=699</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=699"/>
		<updated>2021-10-01T10:35:41Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_protect_external_EDAC_set (SPARC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=698</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=698"/>
		<updated>2021-10-01T10:24:47Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_protect_external_EDAC_set (SPARC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=697</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=697"/>
		<updated>2021-10-01T09:15:40Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Protection Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config              MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=696</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=696"/>
		<updated>2021-10-01T09:04:44Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Logging Manager Directives */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=695</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=695"/>
		<updated>2021-10-01T08:59:17Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Timing Manager directives */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=694</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=694"/>
		<updated>2021-10-01T08:57:06Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_interrupt_handle_register (SPARC) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=693</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=693"/>
		<updated>2021-10-01T08:52:21Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Interrupt Manager Directives */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=692</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=692"/>
		<updated>2021-10-01T08:43:58Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Timer Action Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=691</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=691"/>
		<updated>2021-10-01T08:37:17Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_dataq_create */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=690</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=690"/>
		<updated>2021-10-01T08:34:14Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Data Queue Manager */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=689</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=689"/>
		<updated>2021-10-01T08:27:35Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_reset */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=688</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=688"/>
		<updated>2021-10-01T08:26:20Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_penq_get_size */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=687</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=687"/>
		<updated>2021-10-01T08:24:56Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_get_value */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=686</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=686"/>
		<updated>2021-10-01T08:23:27Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_wait_restart_timeout */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=685</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=685"/>
		<updated>2021-10-01T08:22:12Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_wait_restart */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=684</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=684"/>
		<updated>2021-10-01T08:20:48Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_wait_continue */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=683</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=683"/>
		<updated>2021-10-01T08:19:29Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_signal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=682</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=682"/>
		<updated>2021-10-01T08:18:19Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_sem_create */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=681</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=681"/>
		<updated>2021-10-01T08:16:49Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_mutex_get_value */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=680</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=680"/>
		<updated>2021-10-01T08:16:03Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_mutex_signal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=679</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=679"/>
		<updated>2021-10-01T08:14:54Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_mutex_wait */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=678</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=678"/>
		<updated>2021-10-01T08:13:46Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_mutex_create */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=677</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=677"/>
		<updated>2021-10-01T08:11:57Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_get_info */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=676</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=676"/>
		<updated>2021-10-01T08:10:12Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_kill */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=675</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=675"/>
		<updated>2021-10-01T08:09:02Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_get_status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=674</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=674"/>
		<updated>2021-10-01T08:07:48Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_get_priority */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=673</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=673"/>
		<updated>2021-10-01T08:06:52Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_self */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=672</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=672"/>
		<updated>2021-10-01T08:06:13Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_enable */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=671</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=671"/>
		<updated>2021-10-01T08:05:17Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_disable */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=670</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=670"/>
		<updated>2021-10-01T08:04:14Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_timed_start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=669</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=669"/>
		<updated>2021-10-01T08:02:57Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=668</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=668"/>
		<updated>2021-10-01T08:01:46Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_task_create */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=667</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=667"/>
		<updated>2021-10-01T07:59:40Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* Task Status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=666</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=666"/>
		<updated>2021-10-01T07:58:55Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_check_area */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=665</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=665"/>
		<updated>2021-10-01T07:57:42Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_CPU_sleep */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=664</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=664"/>
		<updated>2021-10-01T07:56:28Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_exit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=663</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=663"/>
		<updated>2021-10-01T07:55:42Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_init_finish */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
// finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=662</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=662"/>
		<updated>2021-10-01T07:53:57Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
 // finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=661</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=661"/>
		<updated>2021-10-01T07:52:07Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_init_finish */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
 // finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
	<entry>
		<id>https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=660</id>
		<title>OCEOS Directives Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.ocetechnology.com/mediawiki/index.php?title=OCEOS_Directives_Reference&amp;diff=660"/>
		<updated>2021-10-01T07:51:01Z</updated>

		<summary type="html">&lt;p&gt;Wiki: /* oceos_init */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
= Directives Reference =&lt;br /&gt;
OCEOS provides a set of directives to the application developer. These directives are detailed below.&lt;br /&gt;
&lt;br /&gt;
== Initialisation Manager ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_init ===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
enum DIRECTIVE_STATUS   oceos_init(&lt;br /&gt;
    const struct application_configuration&lt;br /&gt;
);&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This directive initialises the OCEOS fixed data structures. It is called from application_init()&lt;br /&gt;
in config.c.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;p&amp;gt;Parameters in:  application_configuration structure defined below (oceos.h).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The values if the structure members are overwritten by the application developer #defines for NUMBER_OF_TASKS, NUMBER_OF_MUTEXES, ...etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot; line&amp;gt;&lt;br /&gt;
 /*&lt;br /&gt;
  * Application Configuration Structure&lt;br /&gt;
  *&lt;br /&gt;
  * The application must create a structure of this type,&lt;br /&gt;
  * initialise its fields as appropriate for the application&lt;br /&gt;
  * then pass it to oceos_init().&lt;br /&gt;
  *&lt;br /&gt;
  * It is recommended that fields that are not used are set to 0 or to NULL.&lt;br /&gt;
  *&lt;br /&gt;
  * The structure is not used subsequently by OCEOS,&lt;br /&gt;
  * after oceos_init completes the space used for it can be freed.&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
 struct application_configuration {&lt;br /&gt;
&lt;br /&gt;
  /* addresses to be used used for internal OCEOS data */&lt;br /&gt;
  U32_t            log_address;&lt;br /&gt;
  U32_t            fixed_data_address;&lt;br /&gt;
  U32_t            dynamic_data_address;&lt;br /&gt;
&lt;br /&gt;
  /* used in relation to the system stack */&lt;br /&gt;
  U32_t            stack_start_address;&lt;br /&gt;
  U32_t            stack_lower_bound_address;&lt;br /&gt;
&lt;br /&gt;
  /* user defined functions to handle invalid system state and log 3/4 full */&lt;br /&gt;
  void (*system_error_function)(void *);&lt;br /&gt;
  void (*log_full_function)(void *);&lt;br /&gt;
&lt;br /&gt;
  /* basic application component numbers */&lt;br /&gt;
  unsigned int     number_of_tasks                     : 8;&lt;br /&gt;
  unsigned int     number_of_readyQ_entries            : 8;&lt;br /&gt;
  unsigned int     log_number_of_entries               : 10;&lt;br /&gt;
  unsigned int     number_of_mutexes                   : 6;&lt;br /&gt;
  unsigned int     number_of_counting_semaphores       : 6;&lt;br /&gt;
  unsigned int     number_of_data_queues               : 6;&lt;br /&gt;
  unsigned int     timed_actions_timer_index           : 4; // Must be highest priority timer, on timer unit 0&lt;br /&gt;
  unsigned int     action_time_interrupt               : 8; // Interrupt number for action timer(6 bits should be enough)&lt;br /&gt;
  unsigned int     timed_actions_queue_size            : 8;&lt;br /&gt;
  unsigned int     number_of_user_defined_traps        : 8;&lt;br /&gt;
  unsigned int     sys_time_timer_index                : 4; // Timer index within selected timer Unit&lt;br /&gt;
  unsigned int     interrupt_nesting_enabled           : 1; // Change to interrupt nesting enabled&lt;br /&gt;
  unsigned int                                         : 1; // spare&lt;br /&gt;
  unsigned int     watchdog_timer_index                : 2; // Index of watchdog timer&lt;br /&gt;
  unsigned int     watchdog_window                     : 16;&lt;br /&gt;
  unsigned int     watchdog_timeout;&lt;br /&gt;
 };&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
&lt;br /&gt;
=== oceos_init_finish ===&lt;br /&gt;
 // finalises the fixed data array after all tasks etc. have been created&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_init_finish();&lt;br /&gt;
This directive finishes intitialisation for the fixed data area. It is called after tasks, metexes and semaphores have been created.&lt;br /&gt;
&lt;br /&gt;
=== oceos_start ===&lt;br /&gt;
 // starts OCEOS - usually does not return&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_start(&lt;br /&gt;
    const U32_t * const,// pointer to fixed data array&lt;br /&gt;
    const unsigned int, // taskID. If invalid CPU enters sleep mode&lt;br /&gt;
    void * const        // pointer to data to be passed to task&lt;br /&gt;
 );&lt;br /&gt;
This directive starts OCEOS scheduling and is called after oceis_init_finish(). Parameters passed are:&lt;br /&gt;
*	Pointer to the fixed data area (usually fixed_data declared in config.c)&lt;br /&gt;
*	The task ID of the first task to be executed. Usually this task will start other tasks necessary for the application.&lt;br /&gt;
*	Pointer to be passed to the task above. A null pointer can be passed if the task does not use the pointer.&lt;br /&gt;
&lt;br /&gt;
=== oceos_exit ===&lt;br /&gt;
 // exits OCEOS - terminating functions of all active jobs are called&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_exit();&lt;br /&gt;
&lt;br /&gt;
This directive exits OCEOS terminating all jobs.&lt;br /&gt;
&lt;br /&gt;
=== oceos_CPU_sleep ===&lt;br /&gt;
 // put CPU in sleep mode after ensuring interrupts are enabled&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_CPU_sleep();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive puts the CPU in sleep mode which may be required to save power. &lt;br /&gt;
The watchdog will be disabled and only an interrupt will wake the CPU. &lt;br /&gt;
If the application is required to wake the processor in the future then a timed action can be used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_check_area ===&lt;br /&gt;
 unsigned int oceos_check_area(&lt;br /&gt;
    U32_t * const,      // area to be checked&lt;br /&gt;
    const unsigned int  // area size in 32-bit words);&lt;br /&gt;
&lt;br /&gt;
Directive to check if the area header and end sentinel are o.k. &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to start of fixed data area.&lt;br /&gt;
*	Size of fixed data area&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 indicating that area is good.&lt;br /&gt;
*	Non-Zero with bits set as follows:&lt;br /&gt;
**	Bit 0 - INVALID_VERSION (Invalid OCEOS version)&lt;br /&gt;
**	Bit 1 - INVALID_WORDS_USED (area size does not match area size stored)&lt;br /&gt;
**	Bit 2 - INVALID_END (invalid sentinel at end of data area)&lt;br /&gt;
&lt;br /&gt;
== Task Manager ==&lt;br /&gt;
=== Task Status ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 /* A task's status is returned as below if queried */&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
Valid task states are listed above.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_create ===&lt;br /&gt;
 /* create a task, can only be use before OCEOS starts. */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_create(&lt;br /&gt;
    unsigned int taskID,             // unique, 0 to TASKS_MAX_ID&lt;br /&gt;
    U32_t        priority,           // TASK_MAX_PRIORITY to TASK_MIN_PRIORITY&lt;br /&gt;
    U32_t        threshold,          // TASK_MAX_PRIORITY to priority&lt;br /&gt;
    U32_t        jobs_max,           // 1 to JOBS_MAX&lt;br /&gt;
    BOOLE_t      FP_used,            // whether uses floating point hardware&lt;br /&gt;
    BOOLE_t      initially_enabled,  // whether task enabled initially&lt;br /&gt;
&lt;br /&gt;
    void (*start_function)(void *),  // task start address&lt;br /&gt;
    void (*end_function)(void *),    // start of task end function&lt;br /&gt;
&lt;br /&gt;
    U32_t       time_deadline,       // maximum time to complete (ignore if 0)&lt;br /&gt;
    U32_t       time_mininterstart   // minimum time between start requests&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive populates the data structures for a task. It should be called after application_init()&lt;br /&gt;
and before oceos_init_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It must be called for each task otherwise oceos_start(..) &lt;br /&gt;
will return an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID (0 to 254 and specified a enumerated type in config.h)&lt;br /&gt;
*	integer specifying task priority (1 to 254 where 1 is the highest priority and 254 the lowest)&lt;br /&gt;
*	integer specifying pre-emption threshold (1 to 254). Only higher priority tasks can pre-empt.&lt;br /&gt;
*	integer specifying the maximum number of jobs for this task (1 to 15)&lt;br /&gt;
*	boolean specifying if floating point is used (false=not used). Enabling floating point causes the floating point registers to be saved when the task in pre-empted.&lt;br /&gt;
*	boolean specifying if the task is initially enabled (false is disabled)&lt;br /&gt;
*	pointer to function to be executed on task start&lt;br /&gt;
*	pointer to function to be executed when task ends&lt;br /&gt;
*	integer specifying the maximum time (in us) that the task can run (0 = no limit)&lt;br /&gt;
*	integer specifying the minimum time between task finishing and being restarted (0 = no minimum time)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INTERNAL_ERROR (data area not setup)&lt;br /&gt;
*	TOO_MANY (NUMBER_OF_TASKS in config.h have already been created)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	INVALID_NAME (task ID already used)&lt;br /&gt;
*	INVALID_PRIORITY (incorrect priority)&lt;br /&gt;
*	INVALID_NUMBER (incorrect pre-emption threshold)&lt;br /&gt;
*	INVALID_SIZE (incorrect number of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_start ===&lt;br /&gt;
 /* start a task - create job, pass it data pointer, place on ready queue */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const        // pointer to data&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive starts a job for the specified task. Starting a task involves three main stages&lt;br /&gt;
*	setting up a job&lt;br /&gt;
**	finding a free job entry if available&lt;br /&gt;
**	setting up this entry including passing it the data void&lt;br /&gt;
*	placing the job on readyQ&lt;br /&gt;
*	doing a context switch&lt;br /&gt;
&amp;lt;p&amp;gt;The context switch must be dealt with differently when a task is started from an interrupt handler. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The function should only be called after oceos_start(..)&lt;br /&gt;
has been called.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;IMPORTANT NOTE: Tasks can be started in interrupt services routines but CANNOT be started in trap handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer: data pointer passed to job when task starts&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem with data area, attempt to start disabled task)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
*	RESOURCE_IN_USE (problem placing job on the active queue)&lt;br /&gt;
*	TOO_MANY (job queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_timed_start ===&lt;br /&gt;
 /* schedule a task to start at a specific time */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_timed_start(&lt;br /&gt;
    const unsigned int, // task ID, must be in range 0 to 254&lt;br /&gt;
    void * const,       // pointer to data&lt;br /&gt;
    const U64_t,        // system time at which job should start&lt;br /&gt;
    const U32_t,        // forward tolerance for time&lt;br /&gt;
    const U32_t         // backward tolerance for time&lt;br /&gt;
    U32_t *             // return job_id, to remove this job if needed&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive schedules a task to start execution at a given system time. It should only be called after oceos_start(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying ID of task, must be in range 0 to NUMBER_OF_TASKS - 1&lt;br /&gt;
*	pointer passed to job when task starts&lt;br /&gt;
*	integer (64-bit) specifying system time at which task should start&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the forward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance before the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	&amp;lt;p&amp;gt;integer specifying the backward time tolerance in usecs. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The task can only be started if the current time is within this tolerance after the specified start time.&amp;lt;/p&amp;gt;&lt;br /&gt;
*	Pointer to integer to store the ID of the job to be started.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	UNSATISFIED (invalid start time)&lt;br /&gt;
*	INTERNAL_ERROR (error adding job to timed actions queue)&lt;br /&gt;
*	TOO_MANY (too many jobs already started)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_disable ===&lt;br /&gt;
 /* disable a task and remove any current pending or active jobs */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_disable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive disables a task and removes any current or pending jobs.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initilised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_enable ===&lt;br /&gt;
 /* enable a task - only enabled tasks are scheduled */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_task_enable(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive enables a task. It can only be called after oceos_start(..);&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (incorrect task ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_self ===&lt;br /&gt;
 /* get the taskID of the current job */&lt;br /&gt;
 unsigned int  oceos_task_self();&lt;br /&gt;
&lt;br /&gt;
This directive returns the task ID of the currently executing job.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Returns integer with the task ID.&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_priority ===&lt;br /&gt;
 /* get priority of a task */&lt;br /&gt;
 U8_t  oceos_task_get_priority(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the priority of the specified task ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the priority if the task ID.&lt;br /&gt;
*	TASK_INVALID_PRIORITY (invalid task ID, data area not initialised,)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_status ===&lt;br /&gt;
 /* get status of a task */&lt;br /&gt;
 enum TASK_STATUS  oceos_task_get_status(&lt;br /&gt;
    const unsigned int  // task ID, must be in range 0 to 254&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the status of the specified task ID as a value of enum TASK_STATUS type below.&lt;br /&gt;
 enum TASK_STATUS {&lt;br /&gt;
    TASK_DISABLED,      // cannot be scheduled, and no current jobs&lt;br /&gt;
    TASK_ENABLED,       // can be scheduled, but no current jobs&lt;br /&gt;
    TASK_INVALID,       // task does not exist&lt;br /&gt;
 };&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying task ID&lt;br /&gt;
Return values:&lt;br /&gt;
*	Integer with the task status&lt;br /&gt;
*       TASK_ENABLED (task is enabled, can be scheduled, but no current jobs)&lt;br /&gt;
*	TASK_DISABLED (task is disabled, cannot be scheduled, and no current jobs)&lt;br /&gt;
*	TASK_INVALID (task ID passed is incorrect)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_kill ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Directive to call task end function on current task when undesired behavior was detected,&lt;br /&gt;
  * and exit from job to context switch&lt;br /&gt;
  *&lt;br /&gt;
  */&lt;br /&gt;
  enum DIRECTIVE_STATUS        oceos_task_kill();&lt;br /&gt;
This directive kills the currently executing job. It can be called from &lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;within the task&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the error handler&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;from an interrupt service routine&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can only kill the current job due to its single stack design. Application scenarios where this directive could be used include:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Application regular interrupt checking job status&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If such an application interrupt detected an error in the current job it can call oceos_task_kill() as part of its recovery actions&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;oceos_on_error(..)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS calls oceos_on_error(..) in the case of a system_error. This is an application function contained in config.c where application recovery code is located.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; oceos_task_kill is a possible directive to be used as part of error recovery.&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent, scheduling not started)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area not initialised or inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_task_get_info ===&lt;br /&gt;
 /* Get a struct task_info for task information&lt;br /&gt;
  * return :&lt;br /&gt;
  *          INCORRECT_STATE  if initialisation is not done&lt;br /&gt;
  *          INTERNAL_ERROR   if task information is NULL&lt;br /&gt;
  *          INVALID_ID       if task id is not valid&lt;br /&gt;
  *          NOT_DEFINED      if task_info pointer is NULL&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_task_get_info (&lt;br /&gt;
    const unsigned int task_id,  // Task ID&lt;br /&gt;
    struct task_info *info   // Pointer to struct task_info&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * task info to be used with oceos_task_get_info&lt;br /&gt;
  */&lt;br /&gt;
 struct task_info {&lt;br /&gt;
&lt;br /&gt;
    unsigned int    jobs_current_max  :16;        // maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
    unsigned int    jobs_total        :16;        // number of times this task was started, no roll-over, can be reset&lt;br /&gt;
    unsigned int    jobs_current;                 // Number of task instances currently in use by oceos&lt;br /&gt;
    U32_t           time_max_delay;               // maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
    U32_t           time_max_finish;              // maximum time to finish job execution after starting&lt;br /&gt;
    U32_t           time_max_exec;                // maximum time spent executing&lt;br /&gt;
    U32_t           time_total_exec_low;          // total CPU time used by this task low bits&lt;br /&gt;
    U32_t           time_total_exec_high;         // total CPU time used by this task high bits&lt;br /&gt;
    U32_t           time_min_gap_starts;          // minimum time between job creations, can be reset&lt;br /&gt;
    U32_t           time_min_gap_finish_start;    // minimum time between job ending and new job creation, can be reset&lt;br /&gt;
&lt;br /&gt;
    U32_t           time_last_start;              // time of most recent job creation&lt;br /&gt;
    U32_t           time_last_finish;             // time of most recent job finish&lt;br /&gt;
&lt;br /&gt;
    U32_t           preempt_max;                  // maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
This directive updates the task_info structure for the specified task ID. The elements of the structure are as follows:&lt;br /&gt;
*	jobs_current_max (maximum number of concurrent jobs for task since start)&lt;br /&gt;
*	jobs_total (number of times the task was started)&lt;br /&gt;
*	jobs_current_max (current number of jobs for the specified task)&lt;br /&gt;
*	time_max_delay (maximum time on ready queue before becoming active)&lt;br /&gt;
*	time_max_finish (maximum time to finish job execution after starting)&lt;br /&gt;
*	time_max_exec (maximum time spent executing (see note below))&lt;br /&gt;
*	time_total_exec_low (total CPU time used by this task low 32-bits)&lt;br /&gt;
*	time_total_exec_high (total CPU time used by this task high 32-bits)&lt;br /&gt;
*	time_min_gap_starts (minimum time between job creations)&lt;br /&gt;
*	time_min_gap_finish_start (minimum time between job ending and new job creation)&lt;br /&gt;
*	time_last_start (time of most recent job creation)&lt;br /&gt;
*	time_last_finish (time of most recent job finish)&lt;br /&gt;
*	preempt_max (maximum times any job was pre-empted)&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with task ID&lt;br /&gt;
*	pointer to task_info structure&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area inconsistent or not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (dynamic data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid task ID)&lt;br /&gt;
*	NOT_DEFINED (pointer to task_info structure is NULL)&lt;br /&gt;
Note:&lt;br /&gt;
&amp;lt;p&amp;gt;The task execution times above include time spent in interrupt service routines (ISRs) while the task was executing.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Time spent in ISRs is expected to be a small proportion of the overall task execution time. &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; In the design of OCEOS (ref [SDD]) it was deemed too much of an overhead to accumulate time spent in ISRs.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Mutexes can only be created before scheduling begins and are only used  after scheduling has started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS each mutex has a priority ceiling, the priority of the highest  priority task that uses the mutex.&lt;br /&gt;
OCEOS uses this to ensure that a task that needs a mutex only starts when the mutex is available. As a  result problems such as unbounded priority inversion and deadlocks  cannot occur in OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A mutex has a unique mutex ID, an unsigned integer usually defined in the  application header file as an enum MUTEX_NAME{} thus allowing a  user-friendly name be associated with each mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Mutex IDs are used as indices into both fixed and dynamic data arrays and  must cover the range 0 to ((number of mutexes) -1). This is facilitated  by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex is specified when the mutex is created  and does not change subsequently. Priority ceilings are stored in the  fixed data area as an array U8_t mutexCeilings[]&lt;br /&gt;
indexed by the mutex ID.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt; Mutex dynamic data such as its current state and the job holding it are  stored in the dynamic data area in an array of U32_t mutexDynamic[]&lt;br /&gt;
also indexed by the mutex ID.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If a job holds more than one mutex, these should be acquired and released  in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_create ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_create(&lt;br /&gt;
    unsigned int,       // mutex ID, used as index, must be in range 0 to 62&lt;br /&gt;
    U8_t                // mutex priority ceiling&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a mutex with a specified ID and priority ceiling. It should be called for each mutex up to NUMBER_OF_MUTEXES &lt;br /&gt;
after application_init() and before oceos_init_finish() Note that an error will be returned by oceos_init_finish()&lt;br /&gt;
if not all mutexes have been created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying mutex ID (0 to 62)&lt;br /&gt;
*	byte specifying priority ceiling (0 to 254)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INVALID_NAME (mute ID already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid priority ceiling)&lt;br /&gt;
*	TOO_MANY (all mutexes already created)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_wait ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_wait(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive, if successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created. If the mutex is already held by another task then an error status is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, mutex already held)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent tasks state)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_mutex_signal(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive releases a mutex from a job, restores the previous system priority ceiling, and causes a reschedule. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised)&lt;br /&gt;
*	INTERNAL_ERROR (problem with data area, inconsistent priority ceiling, inconsistent tasks state, mutex held by a different job)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_mutex_get_value ===&lt;br /&gt;
 unsigned int            oceos_mutex_get_value(&lt;br /&gt;
    unsigned int        // mutex ID, must be in range 0 to 62&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current value of a mutex. 0 indicates mutex held by a job, 1 indicates that mutex is not held by any job, any other value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	mutex ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	0 (mutex held by a job)&lt;br /&gt;
*	1 (mutex not held by a job)&lt;br /&gt;
*	INTERNAL_ERROR (data area nt initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid mutex ID)&lt;br /&gt;
&lt;br /&gt;
== Semaphore Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;A counting semaphore has an integer value that is always greater than or equal to zero. This value is set initially when the semaphore is created and modified by atomic wait() and signal()&lt;br /&gt;
operations.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each counting semaphore has a pending jobs queue of pending jobs waiting for the semaphore value to become greater than zero.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When a wait operation is performed the semaphore is decremented and the new value is returned, unless the semaphore is already zero in which case the value remains unchanged.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When the semaphore is signalled its value is incremented, and any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_create ===&lt;br /&gt;
 typedef U8_t  sem_t;&lt;br /&gt;
 /*&lt;br /&gt;
  * sem_t sem_id         Semaphore ID (from 0 to 62)&lt;br /&gt;
  * U16_t max_permits    Number of max permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
  * U16_t count_permits  Starting number of permits available (1 to 4094)&lt;br /&gt;
  * U8_t pending_q_size  MAX Number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
  * BOOLE_t use_timeout  Set to TRUE if semaphore is using timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_create(sem_t, U16_t, U16_t, U8_t, BOOLE_t);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates a counting semaphore. It should be called after application_init() and before oceos_init_data_finish()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The number of semaphores created must equal the NUMBER_OF_SEMAPHORES &lt;br /&gt;
definition in config.h. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying Semaphore ID (from 0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of permits allowed for this semaphore (1 to 4094)&lt;br /&gt;
*	integer specifying the starting number of permits available (0 to 4094)&lt;br /&gt;
*	integer specifying the maximum number of jobs on the q for this semaphore (1 to 254)&lt;br /&gt;
*       boolean specifying if semaphore is using timeout&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	INVALID_NUMBER (invalid no of permits of max jobs)&lt;br /&gt;
*	TOO_MANY (permits exceeds max)&lt;br /&gt;
*	INVALID_SIZE (invalid ma no of jobs)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_signal ===&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_sem_signal(sem_t);                // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Job decrements the number of available permits for semaphore and return SUCCESSFUL&lt;br /&gt;
  * If number of available permits is zero, return UNSATISFIED and job should handle unsuccessful result&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive increments the permits value of the specified semaphore. Any jobs on its pending jobs queue are transferred to the ready queue and also removed from the timed jobs queue if present.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (maximum permits already reached, ready queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_continue ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_continue(sem_t);         // counting semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero, then status UNSATISFIED is returned and the job should handle the unsuccessful result.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (permits value is already zero)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart(sem_t);          // semaphore ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_wait_restart_timeout ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_wait_restart_timeout(sem_t, U64_t);          // semaphore ID and timeout&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive decrements the number of available permits for the specified semaphore. If the number of available permits is zero the job is terminated and restarted when the number of permits has been incremented. If a  timeout is specified and subsequently expires, the job is restarted and status UNSATISFIED is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
*	integer (64-bit) specifying the timeout in microseconds&lt;br /&gt;
Status values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	UNSATISFIED (timeout expired before permits were incremented)&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
*	TOO_MANY (job pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_get_value ===&lt;br /&gt;
 int oceos_sem_get_value(sem_t);             // counting semaphore ID&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * sem_t sem_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the permits value of the specified semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of available permits&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_penq_get_size ===&lt;br /&gt;
 int oceos_sem_penq_get_size(sem_t sem_id);&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Semaphore&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of jobs pending for this semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the current number of jobs on the pending queue&lt;br /&gt;
*	-1 (data area not initialised, OCEOS not started, invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_sem_reset ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_sem_reset (sem_t sem_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the queue to its initial state. It removes all jobs from the pending queue and resets the number of permits to the initial value specified when the semaphore was created.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the semaphore ID (0 to 62)&lt;br /&gt;
Values returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised, system state invalid for this operation)&lt;br /&gt;
*	INTERNAL_ERROR (data area inconsistent, job data inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid semaphore ID)&lt;br /&gt;
&lt;br /&gt;
== Data Queue Manager ==&lt;br /&gt;
&amp;lt;p&amp;gt;Data queues are FIFO (first-in-first-out)  queues of non-null void pointers ordered by arrival time. Each queue has an associated pending jobs queue, and two associated atomic operations, read() and write(). A size() operation gives the number of pointers on the queue, and the create() operation sets the maximum size of the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_create ===&lt;br /&gt;
&lt;br /&gt;
 typedef U8_t dataq_t&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U16_t dataq_size &lt;br /&gt;
  * U16_t pen_q_size &lt;br /&gt;
  * BOOLE_t roll_over&lt;br /&gt;
  * BOOLE_t use_timeout&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_create(dataq_t, U16_t, U16_t, BOOLE_t, BOOLE_t);     // data queue ID and maximum queue size&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive creates the specified data queue with specified queue size and pending jobs queue size.&lt;br /&gt;
Roll-over on the queue can also be enabled/disabled. Roll-over means that if the queue is full new entries will overwrite the oldest ones on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying the data queue to be created (0 to 62)&lt;br /&gt;
*	integer specifying the maximum number of entries of the data queue (1 to 255)&lt;br /&gt;
*	integer specifying the maximum number of pending jobs (1 to 255)&lt;br /&gt;
*	boolean to enable/disable roll-over (0 to disable, 1 to enable roll-over) &lt;br /&gt;
*	boolean specifying if dataq is using a timeout &lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	TOO_MANY (data queue ID too large)&lt;br /&gt;
*	INVALID_NAME (data queue already created)&lt;br /&gt;
*	INVALID_NUMBER (invalid data queue size)&lt;br /&gt;
*	INVALID_SIZE (invalid pending queue size)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_write ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_dataq_write(dataq_t dataq_id, void* data);    // data queue ID and non-null pointer to data&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add a pointer to the end of the data queue. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID&lt;br /&gt;
*	pointer to data&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (data area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (invalid job state)&lt;br /&gt;
*	TOO_MANY (data queue full, pending queue full)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_continue ===&lt;br /&gt;
 void*  oceos_dataq_read_continue(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty NULL is returned.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart(dataq_t dataq_id);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_read_restart_timeout ===&lt;br /&gt;
&lt;br /&gt;
data queue ID&lt;br /&gt;
 /*&lt;br /&gt;
  * dataq_t dataq_id &lt;br /&gt;
  * U64_t timeout, if 0 =&amp;gt; ignored&lt;br /&gt;
  */&lt;br /&gt;
 void* oceos_dataq_read_restart_timeout(dataq_t dataq_id, U64_t timeout);      // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the oldest pointer from the data queue. If the queue is empty the task is put on the pending queue to be restarted when new data is available on the queue. A 64-bit timeout in microseconds can be set, after which the task will be removed from the pending queue and NULL will be returned. If a timeout value of zero is passed then the job will remain on the pending queue until a data queue pointer is available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Jobs restarted will lose any data stored in variables on the stack so it may be necessary for the application to store such data elsewhere so that it is available when the job is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	data pointer to oldest entry on the queue&lt;br /&gt;
*	NULL (queue is empty, data area not initialised, invalid data queue ID)&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of elements in Data Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int oceos_dataq_get_size(dataq_t);                // data queue ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of pointers on the data queue. A negative return value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*	-1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_penq_get_size ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Get Number of Jobs on Pending Q&lt;br /&gt;
  * dataq_t dataq_id&lt;br /&gt;
  */&lt;br /&gt;
 int  oceos_dataq_penq_get_size(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the current number of jobs on the pending queue for the specified data queue ID. A negative value indicates an error.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer whose value is the current number of pointers on the data queue&lt;br /&gt;
*       -1 data area not initialised or inconsistent, invalid data queue ID&lt;br /&gt;
&lt;br /&gt;
=== oceos_dataq_clear ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Reset Data Q&lt;br /&gt;
  * Involves reseting data q and freeing up jobs from pending Q&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_dataq_clear(dataq_t dataq_id);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the specified data queue deleting all entries and clearing jobs from pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying data queue ID (0 to 62)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (memory area not initialised or inconsistent)&lt;br /&gt;
*	INVALID_ID (invalid data queue ID)&lt;br /&gt;
*	INTERNAL_ERROR (inconsistent pending job data)&lt;br /&gt;
&lt;br /&gt;
== Timer Action Manager ==&lt;br /&gt;
This timed action manager provides directives to perform actions at a precise time in the future. The currently supported action types are:&lt;br /&gt;
*	Timed output to memory address or register&lt;br /&gt;
*	Start job which allows a job to be started at a future time (oceos_task_timed_start)&lt;br /&gt;
*	Timeout for data queue pending job (internal)&lt;br /&gt;
*	Timeout for semaphore queue pending job (internal)&lt;br /&gt;
&lt;br /&gt;
=== Action Types ===&lt;br /&gt;
The action types implemented in OCEOS are listed in the enumerated type below. The action types required by the user for oceos_timed_output_add(..) &lt;br /&gt;
are WRITE_ACTION and RMW_ACTION.&lt;br /&gt;
Other action types are provided for information but are not available to the user.&lt;br /&gt;
 enum ACTION_TYPE {&lt;br /&gt;
  INVALID_ACION,&lt;br /&gt;
  START_JOB_ACTION,         // The job was created with start in future. Put job on ready Q&lt;br /&gt;
  DATA_Q_WAIT_ACTION,       // The job is on data_Q pending Q with timeout&lt;br /&gt;
  SEM_Q_WAIT_ACTION,        // The job is on semaphore_Q pending Q with timeout&lt;br /&gt;
  WRITE_ACTION,             // Write value to address&lt;br /&gt;
  RMW_ACTION,               // Read-modify-write Action&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Add job to timed action Q&lt;br /&gt;
  * return -1 if fail&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_number ===&lt;br /&gt;
 int   oceos_timed_jobs_number();          // get number of jobs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of queued jobs setup with oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with the number of jobs in the queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_remove ===&lt;br /&gt;
 int  oceos_timed_jobs_remove(       // remove all jobs of this task from timed actions queue&lt;br /&gt;
                            U32_t);                         // task ID&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified job from the timed jobs queue. The specified job ID is usually one returned by a successful call of oceos_task_timed_start()&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying timed job ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	NOT_CONFIGURED (timed actions not initialised)&lt;br /&gt;
*	INVALID_ID (invalid timed job ID, invalid action ID, not found on readyQ)&lt;br /&gt;
*	UNSATISFIED (problem stopping timed timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
*	OBJECT_WAS_DELETED (timed job was already removed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_jobs_reset ===&lt;br /&gt;
 int  oceos_timed_jobs_reset();           // clear all timed jobs from timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive resets the timer jobs queue and removes all timed job actions.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed jobs system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_add ===&lt;br /&gt;
 int  oceos_timed_output_add(             // add output to timed action queue, return action ID&lt;br /&gt;
                            const enum ACTION_TYPE,         // Action type&lt;br /&gt;
                            const U64_t,                    // system time at which action should be done&lt;br /&gt;
                            const U32_t,                    // forward tolerance for time&lt;br /&gt;
                            const U32_t,                    // backward tolerance for time&lt;br /&gt;
                            const adrs_t,                   // output address&lt;br /&gt;
                            const U32_t,                    // output value&lt;br /&gt;
                            const U32_t,                    // output mask&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive places a specified action type (write or rmw) on the timed output queue to be executed at the specified time in the future. Forward and backward tolerances are specified, and the action will be carried out within these tolerances. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;The target address to be written is supplied along with an output value. The mask is supplied for rmw (read, modify, write) operations on specified bits in the target address. Only the bits in value specified by the mask will be written to the address.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The only output type currently supported is WORD32.&amp;gt;Other types may be supported in the future. The action ID is returned, if successful.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer action types WRITE_ACTION and RMW_ACTION are supported. WRITE_ACTION causes output value to be written to output address. RMW action causes only the bits in value specified by the mask to be written to the output address.&lt;br /&gt;
*	64-bit integer with the scheduled future time at which the action is to be performed.&lt;br /&gt;
*	Integer with forward tolerance in microseconds on the scheduled action time. The action will never be performed in advance of the forward tolerance of the scheduled time.&lt;br /&gt;
*	Integer with backward tolerance in microseconds after the scheduled action time. The action will never be performed later than the backward tolerance after the scheduled time.&lt;br /&gt;
*	Address (32-bit) of the output location. This is the location to which the value will be written.&lt;br /&gt;
*	Integer (32-bit) with the value to be written to the output address.&lt;br /&gt;
*	Integer (32-bit) with the output mask used in the read-modify-write operation.&lt;br /&gt;
Status returns:&lt;br /&gt;
*	Integer with action ID if successful&lt;br /&gt;
*	-1 (unsuccessful, timed outputs not initialised, action queue full, failed to stop timer during add operation, failed to execute output action if the time was already within tolerance)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_number ===&lt;br /&gt;
 int  oceos_timed_output_number();        // get number of timed outputs on timed actions queue&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the number of timed outputs on the timed actions queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Values returned:&lt;br /&gt;
*	integer with number of timed outputs on the action queue&lt;br /&gt;
*	-1 (timed actions not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_remove ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_timed_output_remove(          // remove this output from action queue&lt;br /&gt;
                            const U32_t                     // Index in action array, returned when action was created&lt;br /&gt;
                            );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive removes the specified action ID from the timed outputs queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with action ID&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED (timed action system not initialised)&lt;br /&gt;
*	INVALID_ID (action ID invalid)&lt;br /&gt;
*	OBJECT_WAS_DELETED (action ID was already deleted)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (issue removing from timed_q)&lt;br /&gt;
*	EMPTY (timed queue is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_timed_output_reset ===&lt;br /&gt;
 int oceos_timed_output_reset();         // clear all timed outputs from action queue&lt;br /&gt;
&lt;br /&gt;
This directive clears all timed outputs from the action queue.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	NOT_CONFIGURED  (timed actions system not initialised)&lt;br /&gt;
*	UNSATISFIED (failed to stop timer)&lt;br /&gt;
*	INCORRECT_STATE (timed q is empty)&lt;br /&gt;
&lt;br /&gt;
== Interrupt Manager Directives ==&lt;br /&gt;
&amp;lt;p&amp;gt;Interrupt management is done using BCC calls.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS includes two directives that wrap the corresponding BCC calls so that OCEOS can ensure the application does not use interrupts used by OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_register (SPARC) ===&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_register_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_register(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to register an interrupt using the standard BCC interrupt functions (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to register isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
struct bcc_isr_node:&lt;br /&gt;
 /*&lt;br /&gt;
  * Interrupt node for registering interrupt handler&lt;br /&gt;
  *&lt;br /&gt;
  * This structure is used for registering interrupt handlers with&lt;br /&gt;
  * bcc_isr_register_node() and bcc_isr_unregister_node(). An application shall&lt;br /&gt;
  * not use it if bcc_isr_register() and bcc_isr_unregister() is used.&lt;br /&gt;
  */&lt;br /&gt;
 struct bcc_isr_node {&lt;br /&gt;
        /* BCC private data (do not touch) */&lt;br /&gt;
        void *__private;&lt;br /&gt;
        /* Interrupt source number */&lt;br /&gt;
        int source;&lt;br /&gt;
        /* User ISR handler */&lt;br /&gt;
        void (*handler)(&lt;br /&gt;
                void *arg,&lt;br /&gt;
                int source&lt;br /&gt;
        );&lt;br /&gt;
        /* Passed as parameter to handler */&lt;br /&gt;
        void *arg;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
OCEOS example :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register handler&lt;br /&gt;
  */&lt;br /&gt;
 void fun0(void * ptr){&lt;br /&gt;
    node.source = 12;&lt;br /&gt;
    node.handler = start_task;&lt;br /&gt;
    node.arg = ptr;&lt;br /&gt;
    ret = oceos_interrupt_handle_register(&amp;amp;node);&lt;br /&gt;
    if (SUCCESSFUL != ret) {&lt;br /&gt;
        printf(&amp;quot;ERROR :: Failed to add ISR handler\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    bcc_int_unmask(12);&lt;br /&gt;
    exit(1);&lt;br /&gt;
 } &lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Handler for interrupt&lt;br /&gt;
  */&lt;br /&gt;
 void start_task(void *arg, int source){&lt;br /&gt;
  oceos_task_start(t_harry,arg);&lt;br /&gt;
  oceos_task_start(t_dick,arg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_register_node:&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Register interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_register() with the difference that the&lt;br /&gt;
  * user is responsible for memory management. It will never call malloc().&lt;br /&gt;
  * Instead the caller has to provide a pointer to a preallocated and&lt;br /&gt;
  * initialized ISR node of type struct bcc_isr node.&lt;br /&gt;
  *&lt;br /&gt;
  * The memory pointed to by isr_node shall be considered owned exclusively by&lt;br /&gt;
  * the run-time between the call to bcc_isr_register_node() and a future&lt;br /&gt;
  * bcc_isr_unregister_node(). It means that the memory must be available for&lt;br /&gt;
  * this time and must not be modified by the application. The memory pointed to&lt;br /&gt;
  * by isr_node must be writable.&lt;br /&gt;
  *&lt;br /&gt;
  * This function should be used to install interrupt handlers in applications&lt;br /&gt;
  * which want full control over memory allocation.&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Pointer to user initialized ISR node. The fields source, handler&lt;br /&gt;
  *           and optionally the arg shall be initialized by the caller.&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler installed successfully.&lt;br /&gt;
  * - BCC_FAIL: Failed to install handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_register_node(&lt;br /&gt;
        struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== oceos_interrupt_handle_unregister (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * OCEOS Wrapper around bcc_isr_unregister_node(struct bcc_isr_node *isr_node)&lt;br /&gt;
  * in order to check if user not interfering with OCEOS internal configurations&lt;br /&gt;
  * set the function to be used for the given interrupt&lt;br /&gt;
  * @param struct bcc_isr_node&lt;br /&gt;
  */&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_interrupt_handle_unregister(&lt;br /&gt;
    struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to unregister an interrupt using the standard BCC interrupt function (see section 5.9 of BCC manual). Extracts from bcc.h and OCEOS example below.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to bcc_isr_node structure with the following elements initialised:&lt;br /&gt;
**	Source (interrupt source number)&lt;br /&gt;
**	Handler (interrupt handler address)&lt;br /&gt;
**	Pointer passed to handler&lt;br /&gt;
Return Values are:&lt;br /&gt;
*	SUCCESSFUL (Interrupt handler successfully registered)&lt;br /&gt;
*	NOT_CONFIGURED (Interrupt Manager not initialised)&lt;br /&gt;
*	INVALID_NUMBER (Interrupt source number is used by OCEOS)&lt;br /&gt;
*	INTERNAL_ERROR (BCC failed to unregister isr_node to source number)&lt;br /&gt;
 &lt;br /&gt;
bcc_isr_unregister_node :&lt;br /&gt;
&lt;br /&gt;
 /*&lt;br /&gt;
  * Unregister interrupt handler, non-allocating&lt;br /&gt;
  *&lt;br /&gt;
  * This function is similar to bcc_isr_unregister() with the difference that&lt;br /&gt;
  * the user is responsible for memory management.  It is only allowed to&lt;br /&gt;
  * unregister an interrupt handler which has previously been registered with&lt;br /&gt;
  * bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * isr_node: Same as input parameter to bcc_isr_register_node().&lt;br /&gt;
  *&lt;br /&gt;
  * return:&lt;br /&gt;
  * - BCC_OK: Handler successfully unregistered.&lt;br /&gt;
  * - BCC_FAIL: Failed to unregister handler.&lt;br /&gt;
  */&lt;br /&gt;
 int bcc_isr_unregister_node(&lt;br /&gt;
        const struct bcc_isr_node *isr_node&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
== Timing Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get64 ===&lt;br /&gt;
 // get the current system time (64-bit)&lt;br /&gt;
 U64_t  oceos_time_sys_get64();&lt;br /&gt;
&lt;br /&gt;
Directive to return the OCEOS system time as a 64-bit number. The OCEOS system time is the number of microseconds since OCEOS was started.&lt;br /&gt;
&lt;br /&gt;
=== oceos_time_sys_get32 ===&lt;br /&gt;
 // get the current system time (low 32 bits of 64 bit value)&lt;br /&gt;
 U32_t oceos_time_sys_get32();&lt;br /&gt;
Directive to return the low 32-bits of the OCEOS system time. The lower 32 bits of OCEOS system time (microseconds) rolls over every 71 minutes.&lt;br /&gt;
&lt;br /&gt;
== Logging Manager Directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_add_entry ===&lt;br /&gt;
 // add a log entry (32-bit time is included automatically)&lt;br /&gt;
  enum DIRECTIVE_STATUS   oceos_log_add_entry(&lt;br /&gt;
    enum LOG_ENTRY_TYPE,// 8 bits&lt;br /&gt;
    const unsigned int  // information (24 bits)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to add an entry to the log and add a 32-bit time tamp. Each log entry consists of a type (8-bit), and information (24-bits).&amp;lt;/p&amp;gt;&lt;br /&gt;
OCEOS log types are:&lt;br /&gt;
*	NOT_VALID_ENTRY (value 0 not allowed)&lt;br /&gt;
*	ALL_OK (System OK, information value provides more information)&lt;br /&gt;
*	NO_JOB_FREE (TBD)&lt;br /&gt;
*	READYQ_FULL (The ready queue is full)&lt;br /&gt;
*	MUTEX_WAIT_REPEAT (TBD)&lt;br /&gt;
*	MUTEX_SIGNAL_REPEAT (TBD)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully added to log)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (type or information is invalid)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_remove_entry ===&lt;br /&gt;
 // read and remove the oldest unread log entry&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_remove_entry(&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Directive to remove the oldest unread log entry and copy its contents to the pointer passed. If the log is not empty use the entry at the read index to update the value at the output pointer, returning SUCCESSFUL. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;If the log is empty, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Pointer to struct log_entry here removed entry will be returned.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully removed and returned in pointer)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INCORRECT_STATE (log read or write pointer is inconsistent)&lt;br /&gt;
*	UNSATISFIED (log is empty)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_indexed_entry ===&lt;br /&gt;
 // read the log entry at the given index&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_log_get_indexed_entry(&lt;br /&gt;
    const unsigned int,&lt;br /&gt;
    struct log_entry * const&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the entry at the specified position in the log. The entry is not removed and the log and log indices are not changed. &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;It is intended to allow the log be examined for example after reset. If the index is out of range, set the value at the output pointer to NOT_VALID_ENTRY and return UNSATISFIED.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	Integer containing the log entry to be read&lt;br /&gt;
*	Pointer (struct log_entry type) where entry address will be copied&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (entry successfully retrieved and pointer returned)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	INVALID_NUMBER (invalid entry number passed)&lt;br /&gt;
*	INVALID_ADDRESS (invalid pointer address passed)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_reset ===&lt;br /&gt;
 // clear all log entries and reset to empty&lt;br /&gt;
 enum DIRECTIVE_STATUS oceos_log_reset();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Set all log entries to NOT_VALID_ENTRY and the log to empty, with the read and write indices set to 0 and function called flag 0.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; The log is empty if the index of the next write is the same as the index of the next read.&amp;lt;/p&amp;gt; It does not affect the system status variable&lt;br /&gt;
Note that Traps should be disabled before calling.&lt;br /&gt;
 &lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (log successfully reset)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised or corrupt)&lt;br /&gt;
*	UNSATISFIED (unexpected data corruption)&lt;br /&gt;
&lt;br /&gt;
=== oceos_log_get_size ===&lt;br /&gt;
 // get the number of log entries&lt;br /&gt;
 unsigned int oceos_log_get_size();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of entries in the log according to the current values of the read and write indices. The value will be zero if the current values of the read and write indices are the same.&lt;br /&gt;
&lt;br /&gt;
No parameters.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	LOG_INVALID_SIZE (log data area corrupt)&lt;br /&gt;
*	NOT_CONFIGURED (log data area not initialised)&lt;br /&gt;
&lt;br /&gt;
== Protection Manager ==&lt;br /&gt;
The two memory protection units in the GR716 can be used to restrict write access to memory segments by selected system bus masters (MEMPROT0) and by selected DMA bus masters (MEMPROT1).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Each unit allows four memory segments be defined for write protection. In addition MEMPROT0 can restrict access via the system bus AHB to APB bridges by selected system bus masters and the four DMA units to selected APB bus devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can protect four segments in the range 0x40000000 to 0x4fffffff or the range 0x80000000 to 0x8041ffff, as well as specific APB units.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 can protect four segments in the range 0x30000000 to 0x31000000 and restrict the access of any master on the DMA bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
An attempt to write to a protected area causes an AMBA ERROR response which can cause an interrupt from MEMSCRUB or from one of the AHBSTAT units. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The memory protection manager's directives relate to the EDAC and memory protection features of the GR716. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Support for the external memory scrubber (MEMSCRUB) and the two memory protection units (MEMPROT0/1) is available also from the GR716 BSP. Cobham Gaisler documentation on this support can be found in the GR716 board support package documentation in BCC.pdf, Section 7.25 for MEMSCRUB, Section 7.24 for MEMPROT0/1. Support for the internal memory EDAC and scrubbing and for external memory EDAC is not provided by the GR716 BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The directives here access hardware registers and do not use the BSP. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The internal instruction RAM and data RAM of the GR716 each has its own EDAC and scrubber support internal to the GR716. The internal scrubbers use one 32-bit word per burst and an appropriate number of cycles between bursts should be specified for each scrubber. The scrubbers can be individually configured to cause an interrupt when an uncorrectable error occurs and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The GR716 internal RAM can also be protected from external write accesses by the memory protection unit on the DMA bus (MEMPROT1). The external RAM memory controllers (FTMCTRL0/1) provide EDAC support, with scrubbing provided by the MEMSCRUB unit on the main system bus. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
As the main external memory (FTMCTRL0) uses an 8-bit data bus the high 20% of this RAM is used for the EDAC check bits and cannot be used for data when EDAC is enabled. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
(The GR716-MINI board has 2 MiB of main external RAM accessed via FTMCTRL0 and with EDAC enabled only addresses 0x40000000 to 0x40199997 can be used for data, the check bits are stored at addresses 0x4019999a to 0x401fffff, and addresses 0x40199998 and 0x40199999 cannot be used). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
When using MEMSCRUB this restriction must be taken into account in setting the high address of the scrubbing range. (The GR716-MINI external RAM scrubber range is 0x40000000 to 0x40199997.) &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
On the GR716 the MEMSCRUB unit works in bursts of two 32-bit words, and an appropriate number of cycles between bursts should be specified. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMSCRUB can be configured to cause an interrupt due to correctable or uncorrectable error counts exceeding a pre-set threshold, and if this is done an appropriate handler for Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the internal scrubbers). &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Two memory protection (MEMPROT) units, one for the main system bus, one for the DMA bus, each allow up to four memory segments be defined and can be configured to prevent writes by a specific bus master to a segment. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 controls memory writes via the main memory controller FTMCTRL0 by selected bus masters for addresses 0x40000000 to 0x4fffffff. &amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. If EDAC is in use with FTMCTRL0 the memory area to which access is allowed must include the EDAC check bits as well as the data.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0 can also restrict writes to APB bus addresses in the range 0x80000000 to 0x8041ffff and to specific devices on the APB bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT1 controls memory writes to the GR716 internal RAM from the DMA bus for addresses in the range 0x30000000 to 0x31ffffff.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
Write access permission can be specified on an individual basis for each bus master on the DMA bus.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
MEMPROT0/1 do not themselves cause a trap/interrupt when an attempt is made to write to protected memory, but as well as preventing the write return an AMBA ERROR response which can give rise to an interrupt from AHBSTAT1/0 respectively. If this used an appropriate error handler for  Interrupt Line 63, default Int 19, should be set up in advance (the same interrupt as for the scrubbers).&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. The appropriate clock gating must be set for it to be possible to use FTMCTRL, MEMSCRUB, or the MEMPROT units, and the appropriate GPIO pin selection also configured. This can be done using the GR716 BSP.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
The MEMPROT units themselves must be configured to allow access to the registers of the other devices.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
A handler for Interrupt Line 63, default Int 19, should be set up in advance if required. The directives here assume this has already been done.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
N.B. Where a register contains read-only bits the values set for those bits in the input data used with the directives below must be 0, if not the input will be treated as invalid.&amp;lt;/br&amp;gt;&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_EDAC_set (SPARC)  ===&lt;br /&gt;
 /*&lt;br /&gt;
  * Internal EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 //  sets the internal EDAC control registers&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_EDAC_set(&lt;br /&gt;
    const unsigned int, // internal data memory configuration&lt;br /&gt;
    const unsigned int  // internal instruction memory configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the configuration registers for the GR716 internal data RAM and internal instruction RAM. These registers determine various characteristics, including whether EDAC is enabled. See GR716.h for further information.  As well as setting the registers this routine reads them back to check that they have been set as requested.&amp;lt;/p&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Parameters passed are:&lt;br /&gt;
*	data_config (32-bit integer with configuration for internal data memory)&lt;br /&gt;
*	inst_config (32-bit integer with configuration for internal instruction memory)&lt;br /&gt;
(Note that Input values for read-only bit fields in the registers must be 0)&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (registers successfully loaded with configuration values)&lt;br /&gt;
*	INVALID_NUMBER  (if problem with input parameter)&lt;br /&gt;
*	INVALID_ID (problem loading registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_scrubber_set (SPARC) ===&lt;br /&gt;
 // sets the internal memory scrubber control and interrupt&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_internal_scrubber_set(&lt;br /&gt;
    const unsigned int, // internal data scrubber wash data&lt;br /&gt;
    const unsigned int, // internal data scrubber control&lt;br /&gt;
    const unsigned int, // internal data scrubber configuration&lt;br /&gt;
    const unsigned int, // internal instruction scrubber wash data&lt;br /&gt;
    const unsigned int, // internal instruction  scrubber control&lt;br /&gt;
    const unsigned int  // internal instruction  scrubber configuration&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive sets the configuration registers for the GR716 internal data RAM and  internal instruction RAM scrubbers. These registers determine various scrubbing characteristics, including&lt;br /&gt;
enabling the scrubbers. See GR716.h for further information. As well as setting the registers this routine reads them back to check that they have been set as requested.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Data scrubber wash data (integer)&lt;br /&gt;
*	Data scrubber control (integer)&lt;br /&gt;
*	Data scrubber configuration (integer)&lt;br /&gt;
*	Instruction scrubber wash data (integer)&lt;br /&gt;
*	Instruction scrubber control (integer)&lt;br /&gt;
*	Instruction scrubber configuration (integer)&lt;br /&gt;
&lt;br /&gt;
Note that input bits for read-only fields in the registers should be 0.&lt;br /&gt;
&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL (all O.K.)&lt;br /&gt;
*	INVALID_NUMBER (problem with input parameter)&lt;br /&gt;
*	INVALID_ID (other problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_internal_status_get (SPARC) ===&lt;br /&gt;
 // returns the internal EDAC and scrubber status&lt;br /&gt;
 unsigned int            oceos_protect_internal_status_get(&lt;br /&gt;
    const unsigned int  // 0 =&amp;gt; data memory, 1 =&amp;gt; instruction memory&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of either the data or the instruction configuration register.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Memory type (integer, 0 for data memory, 1 for instruction memory) &lt;br /&gt;
 &lt;br /&gt;
Values returned&lt;br /&gt;
*	unsigned int (value of configuration register, 0 if a problem)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_EDAC_set (SPARC) ===&lt;br /&gt;
 /*&lt;br /&gt;
  * External RAM EDAC control and scrubbing&lt;br /&gt;
  */&lt;br /&gt;
 // sets the main external RAM EDAC control register.&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_EDAC_set(&lt;br /&gt;
    const unsigned int  // EDAC control (FTMCTRL.MCFG3)&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the EDAC control register (MCFG3) in the external memory controller.&lt;br /&gt;
The value input is checked to ensure all read-only bits are 0. The value is not read back for checking as some fields can change. The external EDAC present bit (ME) is checked to make sure it is set.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Value to be set (integer, only low order 12 bits are used)&lt;br /&gt;
 /*&lt;br /&gt;
  *  Return:&lt;br /&gt;
  *      DIRECTIVE_STATUS    SUCCESSFUL      if no problem detected&lt;br /&gt;
  *                          INVALID_NUMBER  if high order 20 bits not 0&lt;br /&gt;
  *                          INCORRECT_STATE if EDAC not present&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_status_get (SPARC) ===&lt;br /&gt;
 // returns the main external RAM EDAC status register (FTMCTRL0.)&lt;br /&gt;
 unsigned int oceos_protect_external_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the contents of the EDAC control register (MCFG3) in the external memory controller (FTMCTRL).&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Return:  unsigned int with value of FTMCTRL.MCFG3 (0 if clock gated off)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_set (SPARC) ===&lt;br /&gt;
 // set the parameters for the external scrubber unit MEMSCRUB&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_external_scrubber_set(&lt;br /&gt;
    const unsigned int, // configuration&lt;br /&gt;
    const unsigned int, // error threshold&lt;br /&gt;
    const unsigned int, // wash data (used twice)&lt;br /&gt;
    const unsigned int, // first range low address&lt;br /&gt;
    const unsigned int, // first range high address&lt;br /&gt;
    const unsigned int, // second range start address&lt;br /&gt;
    const unsigned int  // second range end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the parameters for the external memory scrubber unit MEMSCRUB. BCC provides more extensive driver support for MEMSCRUB than is given here. This may be used as an alternative (cf BCC.pdf Section 25).&amp;lt;/p&amp;gt;&lt;br /&gt;
Notes&lt;br /&gt;
*	On the GR716 the burst length used by MEMSCRUB is 2&lt;br /&gt;
*	The same wash data is written to MEMSCRUB twice to fill its buffer&lt;br /&gt;
*	Values input are checked to ensure all read-only bits are 0&lt;br /&gt;
*	The memory controller should have EDAC enabled (this is not checked)&lt;br /&gt;
 &lt;br /&gt;
Parameters in:&lt;br /&gt;
*	config                    MEMSCRUB.CONFIG  - configuration&lt;br /&gt;
*	error_thresh        MEMSCRUB.ERROR   - interrupt conditions&lt;br /&gt;
*	wash_data           MEMSCRUB.INIT    - wash data (used twice)&lt;br /&gt;
*	range1_low          MEMSCRUB.RANGEL  - range 1 start address&lt;br /&gt;
*	range1_high         MEMSCRUB.RANGEH  - range 2 end address&lt;br /&gt;
*	range2_low          MEMSCRUB.RANGEL2 - range 2 start address&lt;br /&gt;
*	range2_high         MEMSCRUB.RANGEH2 - range 2 end address&lt;br /&gt;
 &lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL if no problem detected&lt;br /&gt;
*	INVALID_NUMBER if any read-only bit is set&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_status_get (SPARC) ===&lt;br /&gt;
 // get the status of the external scrubber MEMSCRUB&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_status_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the external memory scrubber status register MEMSCRUB.STAT as required to re-enable interrupts on task completion.&lt;br /&gt;
&lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns: unsigned int with MEMSCRUB.STAT value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_external_scrubber_position_get (SPARC) ===&lt;br /&gt;
 // returns the current value of the MEMSCRUB position register&lt;br /&gt;
 unsigned int oceos_protect_external_scrubber_position_get();&lt;br /&gt;
&lt;br /&gt;
This directive returns the current value of the position register MEMSCRUB.POS.&lt;br /&gt;
 &lt;br /&gt;
Parameters in: None&lt;br /&gt;
&lt;br /&gt;
Returns:  unsigned int with MEMSCRUB.POS value&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_unit_control (SPARC) ===&lt;br /&gt;
 // Enable or disable protection by a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_unit_control(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive allows enable or disable protection by a MEMPROT unit.&lt;br /&gt;
&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer indicating which MEMPROT unit (0 for main bus, 1 for DMA bus)&lt;br /&gt;
*	integer indicating enable or disable (0 is disable, 1 is enable)&lt;br /&gt;
&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INCORRECT_STATE (problem enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (problem updating MEMPROT registers)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_segment_define (SPARC) ===&lt;br /&gt;
 // Define the range of addresses for a segment of a MEMPROT unit&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_segment_define(&lt;br /&gt;
    const unsigned int, // MEMPROT select, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // start address&lt;br /&gt;
    const unsigned int  // end address&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive defines the range of addresses for a segment of a MEMPROT unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer to select MEMPROT, 0 =&amp;gt; main bus, 1 =&amp;gt; DMA bus&lt;br /&gt;
*	integer with segment number (0-3)&lt;br /&gt;
*	integer with start address&lt;br /&gt;
*	integer with end address&lt;br /&gt;
&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating)&lt;br /&gt;
*	UNSATISFIED (values red back did not match values written)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot0_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT0 segments from masters on main bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot0_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow LEON3 access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow MEMSCRUB access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int, // 1 =&amp;gt; allow DMA bus access to segment, 0 =&amp;gt; deny&lt;br /&gt;
    const unsigned int  // 1 =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT0 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying leon access (1 allows LEON3 access, 0 denies access&lt;br /&gt;
*	 integer specifying  MEMSCRUB access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying DMA bus access to segment (1=allow, 0=deny)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_memprot1_segment_control (SPARC) ===&lt;br /&gt;
 // Control access to MEMPROT1 segments from masters on DMA bus&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_memprot1_segment_control(&lt;br /&gt;
    const unsigned int, // segment number 0 to 3&lt;br /&gt;
    const unsigned int, // DMA bus masters (low 16 bits)&lt;br /&gt;
    const unsigned int  // 1  =&amp;gt; enable segment protection, 0 =&amp;gt; disable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive allows control of access to MEMPROT1 segments from masters on main bus. &amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying  segment (0 to 3)&lt;br /&gt;
*	integer specifying DMA bus masters (low 16 bits)&lt;br /&gt;
*	integer specifying segment protection enabled or disabled (1=enable, 0=disable)&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
=== oceos_protect_APB_devices (SPARC) ===&lt;br /&gt;
 // Control access to APB devices by main bus masters and DMA units&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_protect_APB_devices(&lt;br /&gt;
    const unsigned int, // APB bus  (0,1,2,3)&lt;br /&gt;
    const unsigned int, // CPU (top 16) and Bridge (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // MEMSCRUB (low 16) accessible devices&lt;br /&gt;
    const unsigned int, // DMA0 (top 16) and DMA1 (low 16) accessible devices&lt;br /&gt;
    const unsigned int  // DMA2 (top 16) and DMA3 (low 16) accessible devices&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive control access to APB devices by main bus masters and DMA units&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer specifying APB (0,1,2,3)&lt;br /&gt;
*	integer specifying CPU and Bridge access&lt;br /&gt;
*	integer specifying MEMSCRUB access (low 16)&lt;br /&gt;
*	integer specifying DMA0 and DMA1 access&lt;br /&gt;
*	integer specifying DMA2 and DMA3 access&lt;br /&gt;
Status returned:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
*	INCORRECT_STATE (error enabling clock gating for device)&lt;br /&gt;
*	UNSATISFIED (did not read back correctly)&lt;br /&gt;
&lt;br /&gt;
== FDIR Manager directives ==&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_get ===&lt;br /&gt;
 // returns the value of the system state variable&lt;br /&gt;
 U32_t  oceos_system_state_get();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive returns the value of the system state variable.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Return values:&lt;br /&gt;
*	integer with value of system state variable&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_state_set ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_state_set(&lt;br /&gt;
    U32_t               // new value of system state variable&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This directive sets the system state variable and stores the previous value.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	integer with value of written&lt;br /&gt;
Status returns are:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	STATUS_INVALID (data area corrupt or not initialised)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_init (SPARC) ===&lt;br /&gt;
 enum DIRECTIVE_STATUS   oceos_system_watchdog_init(&lt;br /&gt;
    BOOLE_t,            // whether enabled initially&lt;br /&gt;
    U32_t,              // watchdog timeout&lt;br /&gt;
    U8_t                // watchdog window&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;p&amp;gt;This directive initialises the watchdog. The watchdog window reload value is in the control register. Large window sizes make resets more likely.&amp;lt;/p&amp;gt;&lt;br /&gt;
Parameters in:&lt;br /&gt;
*	Boolean specifying whether watchdog is initially enabled (1 for enabled, 0 for disabled)&lt;br /&gt;
*	Integer specifying watchdog timeout value&lt;br /&gt;
*	Byte specifying window size&lt;br /&gt;
Status returns:&lt;br /&gt;
*	SUCCESSFUL&lt;br /&gt;
*	INVALID_NUMBER (error in input parameters)&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_enable (SPARC) ===&lt;br /&gt;
 // enable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_enable();&lt;br /&gt;
&lt;br /&gt;
This directive enables the watchdog which will use timeout and window values setup previously.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_disable (SPARC) ===&lt;br /&gt;
 // disable the system watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_disable();&lt;br /&gt;
&lt;br /&gt;
This directive disables the system watchdog.&lt;br /&gt;
Parameters in: None&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_ticks_remaining (SPARC) ===&lt;br /&gt;
 // number of ticks remaining until watchdog timeout&lt;br /&gt;
 unsigned int  oceos_system_watchdog_ticks_remaining();&lt;br /&gt;
&lt;br /&gt;
This directive returns the number of ticks to watchdog timeout.&lt;br /&gt;
&lt;br /&gt;
=== oceos_system_watchdog_reset (SPARC) ===&lt;br /&gt;
 // reset the watchdog&lt;br /&gt;
 enum DIRECTIVE_STATUS  oceos_system_watchdog_reset(&lt;br /&gt;
    BOOLE_t             // whether to enable or disable after reset&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
This directive resets the watchdog allowing it to be enabled or disabled after reset.&lt;br /&gt;
Status return: SUCCESSFUL&lt;br /&gt;
&lt;br /&gt;
== OCEOS Data Areas ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;All operating systems require data space to hold various settings and the current states of tasks and other components. Most operating systems also require a separate stack for each task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has been designed to minimise these data memory requirements and to provide clear definitions of data memory use.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS uses a single system stack shared with the application instead of one stack per task, a major space saving.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The other data space used by OCEOS can be divided into three areas&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the fixed data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the dynamic data area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;the log area&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The sizes of these areas depend on the number of tasks etc. but are constants for a given application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not use dynamic memory allocation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each area is 32-bit aligned, starts with a constant 32-bit sentinel (OCEOS_VERSION) and ends with a constant 32-bit sentinel (END_SENTINEL). The size of an area, in 32-bit words, is calculated by OCEOS and stored by OCEOS immediately after the initial OCEOS_VERSION constant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS does not allow tasks or other components be created after scheduling begins, so much of its configuration data is fixed once all tasks etc. have been created and can be stored in an area that does not change. This fixed data area is initialised by oceos_init(), updated as tasks etc. are created, and finalised with the addition of a checksum by oceos_init_finish(). The general layout of this area is always the same, as described below, its actual size depends on the number of tasks etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs information about tasks and their associated jobs and other components is stored in the dynamic data area. The general layout of this area is always the same, as described below, its actual size depends on the number of tasks, maximum jobs for each task, etc.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As OCEOS runs a system state variable and system log are maintained and updated. These are stored in the log area, which may be placed in external non-volatile memory if this is available. The general layout of this area is always the same, as described below, its actual size depends on the system log size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The start address of each area is 32-bit aligned and is placed by the application in the configuration structure (.fixed_data_address, .dynamic_data_address, .log_address). OCEOS sets up each area, placing the sentinels at the start and end of each area and the size of the area (in 32-bit words) immediately after the initial sentinel.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In many applications it will be convenient to allocate space for the three areas as arrays of 32-bit words. The start addresses of these arrays are then placed in the configuration structure as above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To define these arrays their sizes (number of 32-bit words) are needed.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Although OCEOS provides those sizes, as indicated above, it can only do so after all tasks etc. have been created. The array sizes however are required when the arrays are defined, which is before any call to OCEOS is made.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The simplest approach is to initially use overestimates of the array sizes, start using OCEOS, read the second word in each area to get the actual sizes, and restart after re-defining the arrays with these sizes. The sizes can be read and output by application code or using the DMON monitor “oceos” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To find the precise sizes of the three OCEOS data areas the application developer should define values for the number of tasks, mutexes, etc. Next, build a skeleton OCEOS application with the number of tasks, mutexes, semaphores, etc specified. Make sure the initial estimates for the three data areas are overestimates e.g. 0x1000 for each. To run the application tasks, semaphores, mutexes,…etc must be created. Below are examples of DMON output, config.h, and application code.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:areas_sizes.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:header_file_image.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Data_printing.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example application to display data area sizes is provided with OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
DATA AREA LAYOUTS&lt;br /&gt;
&amp;lt;p&amp;gt;The design of OCEOS makes the contents of its data areas readily visible to an application. It is&lt;br /&gt;
straightforward to determine the details of state of the system should it be necessary to do so.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each data area is made up of a number of fields whose sizes depend on the particular application but&lt;br /&gt;
whose general layout is invariant.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The layout of each area is described in oceos_areas.h which also provides the offset at which each&lt;br /&gt;
field in an area is located if the above labels are defined before oceos_areas.h is included.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each field starts at a 32-bit boundary, so treating an area as an array of 32-bit words any field can be&lt;br /&gt;
accessed by simply use the offset as an index into the array.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Data areas layout in memory ===&lt;br /&gt;
&lt;br /&gt;
[[File:memory_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Data Areas Layout ===&lt;br /&gt;
&lt;br /&gt;
[[File:data_areas_layout.jpg]]&lt;br /&gt;
&lt;br /&gt;
= Error messages =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; Applications written to use OCEOS are a combination of tasks calling OCEOS directives. All directives&lt;br /&gt;
return a status value from the enumerated type below (which is based on RTEMS codes). The meaning of the directive status returned depends on context and the called directive.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 /* Status codes returned by OCEOS directives (RTEMS based) */&lt;br /&gt;
 enum DIRECTIVE_STATUS {&lt;br /&gt;
 SUCCESSFUL, // completed as expected&lt;br /&gt;
 TASK_EXITTED,&lt;br /&gt;
 MP_NOT_CONFIGURED,&lt;br /&gt;
 INVALID_NAME,&lt;br /&gt;
 INVALID_ID,&lt;br /&gt;
 TOO_MANY,&lt;br /&gt;
 TIMEOUT,&lt;br /&gt;
 OBJECT_WAS_DELETED,&lt;br /&gt;
 INVALID_SIZE,&lt;br /&gt;
 INVALID_ADDRESS,&lt;br /&gt;
 INVALID_NUMBER,&lt;br /&gt;
 NOT_DEFINED,&lt;br /&gt;
 RESOURCE_IN_USE,&lt;br /&gt;
 UNSATISFIED,&lt;br /&gt;
 INCORRECT_STATE,&lt;br /&gt;
 ALREADY_SUSPENDED,&lt;br /&gt;
 ILLEGAL_ON_SELF,&lt;br /&gt;
 ILLEGAL_ON_REMOTE_OBJECT,&lt;br /&gt;
 CALLED_FROM_ISR,&lt;br /&gt;
 INVALID_PRIORITY,&lt;br /&gt;
 INVALID_CLOCK,&lt;br /&gt;
 INVALID_NODE,&lt;br /&gt;
 NOT_CONFIGURED,&lt;br /&gt;
 NOT_OWNER_OF_RESOURCE,&lt;br /&gt;
 NOT_IMPLEMENTED,&lt;br /&gt;
 INTERNAL_ERROR,&lt;br /&gt;
 NO_MEMORY,&lt;br /&gt;
 IO_ERROR,&lt;br /&gt;
 PROXY_BLOCKING,&lt;br /&gt;
 EMPTY,&lt;br /&gt;
 FAILED_TO_SET_REGISTER&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= OCEOS Application Notes = &lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; This section contains some tips for application developers. &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Directives that restart tasks ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Some OCEOS directives access a resource which, if not available, cause the task to be restarted when the resource has changed state e.g. oceos_dataq_read_restart, oceos_sem_wait_restart. Tasks restarted will lose any data stored in local variables so it may be necessary for the application to store such data elsewhere so that it is available when the task is restarted.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mutex priority ceilings ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The priority ceiling of a mutex ensures that a task holding a mutex cannot be pre-empted by a higher priority task looking for the same mutex. Note that it is the application developer’s responsibility to ensure the correct priority ceiling is setup when the mutex is created. The priority ceiling should be set to the value of the highest priority task using the mutex.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Task local/global storage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; In a RTOS tasks usually start, run for a finite period, then exit. A task involving an endless loop must suspend waiting for a resource at least once around the loop, otherwise it will lock out lower priority tasks. Unless of course it itself is the lowest priority ‘idle’ task, when this lock out doesn’t matter.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As a task runs it stores data in local variables, in most RTOS on its own stack. When a task suspends this locally stored data remains available and can be used by the task when it continues. On exit this local data is lost. Hence if data acquired by a task is to be used by it the next time it starts this data must be stored globally.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A typical example might be to keep track of the total number of things the task has processed.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global integer for the total count, set up and initialised to 0 before the task first starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. unsigned int total = 0U;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Each time the task runs it keeps a count and before it exits uses this to update total&amp;lt;blockquote&amp;gt; &amp;lt;p&amp;gt;e.g total += count; &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;if (total &amp;lt; count) total = UINTMAX_C; // assuming predefined&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;This is all that is needed if all tasks that update total have the same priority and there is only one CPU. (It is assumed that an RTOS does not do time slicing between tasks with the same priority.)&amp;lt;/p&amp;gt;&lt;br /&gt;
If tasks with different priorities can update total or there are multiple CPUs then precautions must be taken to avoid a lost update&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;e.g. disable interrupts on all CPUs remembering previous states&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; update total&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;restore all interrupts to their previous states&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another scenario in which a task will need to store data globally is when it has acquired data from a sensor or other source and has to exit before it can complete processing the data. The data needs to be stored globally so that the task can acquire it again when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A flag can be used by the task to check if the data has already been acquired, in which case it uses the globally stored data rather than acquiring new data. Once use of the global data is completed the task must reset this flag.&amp;lt;/p&amp;gt; &lt;br /&gt;
&amp;lt;p&amp;gt;This would require&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global flag for the state of this globally stored data, set to ‘false’ before the task first starts&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. Boole_t my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A global structure for the data (this could incorporate the flag) set up before any task starts &lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. struct my_data data;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;Logic in the task to use the already stored data if any&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. if(!my_data_already_obtained) {&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;my_data_already_obtained = (data = obtain new data)} // atomic&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt; &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;if (my_data_already_obtained) process the data&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Once data processing is complete the task resets the flag&lt;br /&gt;
&amp;lt;blockquote&amp;gt;e.g. my_data_already_obtained = FALSE;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can acquire the data, tasks are basically in competition to acquire it and each task should have its own ‘xx_data_already_obtained’ flag and its own structure for holding the data. With only one CPU (and no time slicing between tasks of the same priority) this can be relaxed slightly to one flag and one structure per priority rather than per task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Another example might be where a task reads data from a queue and has to exit before it can use the data, but the data needs to be used by the task when it restarts rather than being discarded.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using e.g. an OCEOS data queue (which contains void pointers), no flag is needed as the pointer itself can fulfil that role as well as holding the last item read from the queue by the task:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; A global void pointer for use by the task is initialized to ‘NULL’ before any task starts &amp;lt;blockquote&amp;gt;e.g. void * my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Logic in the task to use the previously read data (if any) or read fresh data &amp;lt;blockquote&amp;gt; e.g. if(NULL == my_last_read) my_last_read = (read the OCEOS data queue) &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Data processing &amp;lt;blockquote&amp;gt; e.g. if(NULL != my_last_read) { process the data at my_last_read} &amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Once data processing is complete the task resets my_last_read &amp;lt;blockquote&amp;gt;e.g. my_last_read = NULL;&amp;lt;/blockquote&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If different tasks can read the data queue, tasks are basically in competition to acquire the data and each task will require its own ‘xx_last_read’. As above this can be relaxed slightly for one CPU to one per priority assuming there is no time slicing between tasks of the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. If there are multiple CPUs the above will need to be modified.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;All of the above apply generally and except for the OCEOS data queue are not specific to OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Specific to OCEOS&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the context of the need for global storage OCEOS differs from many other RTOS in two ways&amp;lt;/p&amp;gt;&lt;br /&gt;
# An OCEOS task may be forced to exit rather than suspending when a counting semaphore or data queue item it needs is not available. It then restarts automatically when the item becomes available, rather than continuing from where it was as with other OS.&lt;br /&gt;
# OCEOS allows the same task be used to process different devices of the same type, rather than needing a different task for each device&lt;br /&gt;
&lt;br /&gt;
OCEOS forced to exit:&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS, a wait operation on a counting semaphore can cause the task to suspend at that point and wait until the counting semaphore is signalled, it then resumes from where it was suspended&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Similarly for an attempt to read a data queue when the data queue is empty.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In most RTOS this behaviour is made possible by each task having its own stack on which the local data remains stored while the task is suspended waiting. Each counting semaphore and data queue also has a pending queue of tasks waiting to continue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS has a single system stack shared by all tasks, a significant space saving. This is used by tasks for their local data as they execute, but this space cannot be retained while a task stops and waits for something to become available as a lower priority task can then resume.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As a result In OCEOS tasks cannot be suspended waiting for something to be available. Instead an OCEOS application can choose either to ‘continue’ or to ‘restart’.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If the ‘continue’ option is used an appropriate status code is returned and the application continues taking into account the unavailability of the sought item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The ‘restart’ option causes the task to exit and be placed on the pending queue of the counting semaphore or data queue. This is similar to what happens when a task waits in other RTOS, but now the task will restart rather than continuing and its previous local data has been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hence if the ‘restart’ option is chosen and it is desired to reuse some already acquired data when the task restarts, any already acquired data should be globally stored before ‘restart’ is used, as described in the earlier general examples above. (A timeout can be specified with the restart.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Using the same task with various devices&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In many system there are multiple instances of the same unit. Rather than having different tasks to handle each unit, OCEOS allows the same task be used as the processing is similar.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The distinction between the units is made by passing the task a pointer to a specific structure associated with the specific unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These structures are global, usually one instance of a particular structure for each unit of a particular type. They are set up by the application, which also may initialise some of their fields. They are usually set up and initialised before OCEOS starts, their contents are not restricted by OCEOS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Each unit structure will typically give register addresses for the unit and provide space for global storage of information specific to that unit such as the time it last caused an interrupt or the total number of interrupts it has caused.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically an OCEOS task is started as a result of an interrupt from a unit. The interrupt handler identifies which task should be started to handle this type of unit, and identifies the specific unit structure associated with the unit that caused the interrupt.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler may store further information in the unit’s structure, such as the time at which the unit last interrupted, the minimum time between interrupts, or other information as determined by the application in setting up the interrupt handler.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler then passes the task ID and a pointer to the specific unit structure to OCEOS with a request to start the task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;If subsequently the task has to exit prematurely due to e.g. a counting semaphore being unavailable, both the task and the unit structure are put on the pending queue, and when the task is restarted by e.g. signalling the counting semaphore it can complete the processing for the unit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before e.g. waiting on a counting semaphore the task can if appropriate update the information in the unit structure, perhaps setting a flag in the structure to indicate to the interrupt handler when the next interrupt occurs that processing of the previous interrupt from the unit was incomplete. (The unit structures are in global storage.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a the task will only update a unit structure with information the task has gathered specific to the unit associated with the structure. More general information the task has gathered, e.g. by reading from an OCEOS data queue, will be stored typically in a global variable or structure associated with the task (or with the task priority) as described in the earlier examples above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The application developer is free to choose what approaches are taken in order to make the previous information available to the task when next it starts.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Example:&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A simple example involves a low priority task putting an item pointer on a data queue and then starting a higher priority task which uses the item.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task reads the data queue but then waits on a semaphore and as this is 0 has to exit and will restart when the low priority task signals the counting semaphore.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In order to ensure the data from the queue is available when it restarts, the high priority task saves it in global memory before doing the wait on semaphore, and on starting checks to see if data is available in the global storage before reading from the data queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(Many other permutations of these activities are possible)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Two tasks, t_tom and t_dick, one counting semaphore s_do_now, one data queue d_items, and in global memory data storage item_store_ptr.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom is the low priority initial task passed to OCEOS when starting:&amp;lt;/p&amp;gt;&lt;br /&gt;
:::t_tom loops forever&lt;br /&gt;
:::::&amp;lt;p&amp;gt; Output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Ensure the global storage item_store_ptr has been cleared&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Place an item pointer on the data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Start the high priority task t_dick.&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;Output a message Signal the semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick is the higher priority task&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;If item_store_ptr is NULL&amp;lt;/p&amp;gt;&lt;br /&gt;
:::::&amp;lt;p&amp;gt;update with value read from data queue d_items using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;wait on counting semaphore s_do_now using restart option&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;output a message involving data read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;clear item_store&amp;lt;/p&amp;gt;&lt;br /&gt;
:::&amp;lt;p&amp;gt;exit&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Expected behaviour: (illustrated by various messages at various stages)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom adds item to data queue d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom starts t_dick causing itself to be immediately pre-empted by t_dick&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick starts and as d_items is not empty updates item_store_ptr with pointer read from d_items&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick waits on counting semaphore s_do_now and exits as this is 0, going on pending queue&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom continues and signals the counting semaphore s_do_now&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_dick restarts, processes the data pointed to by item_store_ptr and exits&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;t_tom goes back to start of loop&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Using OCEOS the basic application structure would be&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Two tasks:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick (ID=1)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Priorities:&lt;br /&gt;
|&amp;lt;p&amp;gt;t_tom: 9&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; t_dick: 8 (highest in this case)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Max jobs:&lt;br /&gt;
|1 in each case (in general recommended this is &amp;gt;=2)&lt;br /&gt;
|-&lt;br /&gt;
|ReadyQ max entries:&lt;br /&gt;
|2 ( total of ‘Max jobs’, no point having more than this)&lt;br /&gt;
|-&lt;br /&gt;
|Counting Semaphore:&lt;br /&gt;
|&amp;lt;p&amp;gt;s_do_now (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Initial values:&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|1 &amp;lt;p&amp;gt;(at most one instance of the high priority task, this is only restarted by the&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;low priority task after the previous start has finished)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Data Queue:&lt;br /&gt;
|&amp;lt;p&amp;gt;d_items (ID=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;(names are an enumerated type, IDs are allocated automatically)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (the high priority task removes the item before the low priority task can add a new item&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|PendingQ size:&lt;br /&gt;
|&amp;lt;p&amp;gt;1 (only one instance of the high priority task can be waiting for an item)&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Global data storage&lt;br /&gt;
|void * item_store_ptr&lt;br /&gt;
|-&lt;br /&gt;
|Application functions&lt;br /&gt;
|&amp;lt;p&amp;gt;tom(),&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;dick() These carry out the task actions described above&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Header&lt;br /&gt;
|&amp;lt;p&amp;gt;app_config.h should be updated to correspond to the above&amp;lt;/p&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the above, the minimum sizes consistent with the application have been used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general it is recommended that the ‘Max jobs’ for each task be at least two, to cater for a new instance of a task being started before a previous instance has finished. In this simple case that cannot happen, but in general it may happen for some unanticipated reason, particularly when tasks are started by interrupt handlers.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The number of ready queue entries need never be more than the maximum number of task instances that can be in existence at any one time. This can never exceed the total of the ‘Max jobs’, and in most cases will be significantly less than this (in OCEOS it cannot exceed 254). In this case it must cater for two task instances having been started and not being finished at the same time.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The initial value of the counting semaphore is 0, as a result the high priority task does not progress the first time it reads the semaphore but exits and goes on the semaphore pending queue.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The high priority task will also be unable to progress if the data queue is empty when it starts but in this case something is always placed on the queue before the high priority task is started.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DMON debug support for OCEOS ==&lt;br /&gt;
&lt;br /&gt;
DMON commands list:&lt;br /&gt;
&lt;br /&gt;
* oceos info&lt;br /&gt;
* oceos log &amp;lt;last | all&amp;gt;&lt;br /&gt;
* oceos state&lt;br /&gt;
* oceos itask &amp;lt;taskID | all&amp;gt;&lt;br /&gt;
* oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt;&lt;br /&gt;
* oceos cpuload &amp;lt;status|enable|disable&amp;gt;&lt;br /&gt;
* traptable [svt | mvt]&lt;br /&gt;
* load &amp;lt;fill&amp;gt; [filename]&lt;br /&gt;
* stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== oceos info ===&lt;br /&gt;
&lt;br /&gt;
Display oceos configuration information. Should be called after oceos_start() directive.&lt;br /&gt;
&lt;br /&gt;
* checks weather log, fixed and dynamic data areas were not overwritten by application at initialisation phase&lt;br /&gt;
* displays the size of log, fixed and dynamic data section that application used, can be used by user to adjust these data area sizes for building application&lt;br /&gt;
* displays oceos configurations&lt;br /&gt;
* displays pointers to data structures of oceos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See ''oceos info'' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_info_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos log &amp;lt;last | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display last log message or all log messages. Default is last log message. DMON finds log area start symbol, number of entries, read and write indexes and displays log entries in latest entries first order.&amp;lt;/p&amp;gt;&lt;br /&gt;
Each entry contains:&lt;br /&gt;
* time the log entry was made&lt;br /&gt;
* entry type&lt;br /&gt;
* entry comment&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log last '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_last_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos log all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_log_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos state ===&lt;br /&gt;
&amp;lt;p&amp;gt;Display system state variables. OCEOS has two system state variables. One variable can be reset by oceos directive, but second is preserved to track any issues occurred while oceos was running. DMON translates system state flags and displays to the user.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos state command '' example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_state_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos itask &amp;lt;taskID | all&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display task information for task with ID or for all tasks in oceos. Default is all task information.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Available information:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|location in memory&lt;br /&gt;
|pointer to task dynamic and pointer to task fixed blocks&lt;br /&gt;
|-&lt;br /&gt;
|taskId&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task priority&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|task threshold&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsMax&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeDeadline&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|timeMinBetweenStarts&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrent&lt;br /&gt;
|current number of jobs created, &amp;lt;= jobsMax&lt;br /&gt;
|-&lt;br /&gt;
|status&lt;br /&gt;
|Enum TASK_STATUS&lt;br /&gt;
|-&lt;br /&gt;
|jobsCurrentMax&lt;br /&gt;
|maximum number of current jobs for this task, no roll over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|jobsTotal&lt;br /&gt;
|number of times this task was started, no roll-over, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeCurrentExec&lt;br /&gt;
|execution time so far of current job&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxDelay&lt;br /&gt;
|maximum time job is waiting on ready queue before becoming active&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxFinish&lt;br /&gt;
|maximum time to finish job execution after starting&lt;br /&gt;
|-&lt;br /&gt;
|timeMaxExec&lt;br /&gt;
|maximum time spent executing&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecLow&lt;br /&gt;
|total CPU time used by this task low bits&lt;br /&gt;
|-&lt;br /&gt;
|timeTotalExecHigh&lt;br /&gt;
|total CPU time used by this task high bits&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapStarts&lt;br /&gt;
|minimum time between job creations, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeMinGapFinishStart&lt;br /&gt;
|minimum time between job ending and new job creation, can be reset&lt;br /&gt;
|-&lt;br /&gt;
|timeLastStart&lt;br /&gt;
|time of most recent job creation&lt;br /&gt;
|-&lt;br /&gt;
|timeLastFinish&lt;br /&gt;
|time of most recent job finish&lt;br /&gt;
|-&lt;br /&gt;
|preemptMax&lt;br /&gt;
|maximum times any job was pre-empted, no roll-over, can be reset&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask 0 '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_0_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos itask all '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_itask_all_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos status &amp;lt;rq | dpq | spq | tapq&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Display oceos status i.e. number of tasks on ready queue (rq), number of tasks on pending data queue (dpq), number of tasks on pending semaphore queue (spq) and number of tasks on timed action queue (tapq). Default “oceos status” is number of tasks on each queue. And then user can get more details about tasks on particular queue by passing switch to “oceos status” command.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status rq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_rq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status dpq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_dpq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status spq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_spq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;See '' oceos status tapq '' command example below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_status_tapq_printout.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== oceos cpuload &amp;lt;status|enable|disable&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Enable/Disable display of CPU Load Graph at interval 1000 ms or check status. Updated while OCEOS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the CPU load enabled graphs below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_cpu_load_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; See the Task Statistics graph for task 0 to 9 below: &amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_4.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[File:oceos_task_statistic_graph_5.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== traptable [svt | mvt] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;DMON displays content of trap table (interrupt number =&amp;gt; trap handler) and translates address to symbols if available.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== load &amp;lt;fill&amp;gt; [filename] ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is extension to load command to fill memory from _bss_end to begging of stack with 0xCAFEBABE. When program stops user can use DMON command “stack check” to see how far stack was used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== stack &amp;lt;check&amp;gt;&amp;lt;lowerBound&amp;gt;&amp;lt;cpuID&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Extension to stack command to check how far stack was grown, can be used when program stops after “load fill” command. User can pass lower bound as parameter. If lower bound parameter is not passed _bss_end symbol is used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= OCEOS Device Support =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In OCEOS a device is typically handled by a task, but it may not be necessary to have a different task for each device. If multiple devices are processed in a similar way one task with its maximum number of jobs at least equal to the number of devices may be enough. When the task is started, typically by an interrupt handler, it is passed a data structure specific to one device and the job then created processes that specific device. For example, the six GR716 UARTs might all be handled by one task.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Separate tasks will be needed however (even for devices of the same type) if different priorities are required for processing different devices as all devices processed by one task are processed with the same priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In a GR716 application that uses OCEOS, device support will typically have three main parts:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Initialisation routines. These are typically called from the main application to&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set up the device’s clock gating control so that it is disabled initially&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt with the specific device and disable this&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;associate a specific interrupt handler with this interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;usually create a data structure associated with each specific device instance&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the clock gating control so that the device can be configured and function&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the GPIO control to map shared GPIO pins to the device as appropriate&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;set the parameters of the device itself&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;use memory protection to protect the device settings&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Interrupt handler code to deal with immediate processing requirements. If this starts a task it typically updates the device specific data structure and passes a pointer to this to the task.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Tasks:&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;A device handler task typically started by the interrupt handler. The job thus created is passed a pointer to the device specific data structure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;An idle task, which clears any pending device interrupt, enables the device interrupt, and then loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;BCC provides support for many of the initialisation routines, with in some cases OCEOS providing wrappers primarily for checking purposes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;It should be noted that the initialisation routines, data structure, interrupt handler and tasks are part of the application software and are not part of OCEOS itself.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General Design Considerations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Typically a device will cause an interrupt, the handler will determine the data structure associated with the device, update this, and if appropriate start a task, passing it a pointer to the data structure. The interrupt handler then exits, the job created will execute at a later time dependent on priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, the interrupt handler should be kept as short as possible, and any significant processing of data be relegated to a task, or sequence of tasks (in OCEOS tasks can be chained).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In general, an interrupt handler will only start a task in certain conditions, for example when a buffer into which incoming data is placed is becoming full.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;When data is being buffered, using a circular buffer, or using double buffering may be advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Careful analysis will be needed to determine the appropriate interrupt priority and the appropriate task priority. These will vary from application to application and are likely to depend on the relative loads on different devices on the systems. A worst-case analysis approach seems advisable.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example - Using a UART on the GR716 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This example uses a UART application to illustrate the main steps involved in GR716 device support.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;There are six APBUARTs on the GR716, and APBUART2 is used here.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 will receive an incoming stream of characters that are to be buffered with a buffer size of 255 characters and passed to a task for processing. If the buffer becomes full older entries are not to be overwritten, newer entries are to be dropped and an error indicated.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Commands requiring action may be included in the data stream and may consist of one or more characters. Commands should be acted upon as soon as possible after being received. A delay of no more than eight character times is the maximum acceptable, and the ordering of commands and data must be preserved.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Even parity is to be used, with one stop bit and a baud rate of 38,400. Flow control is not used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Parity errors, a break condition on the RXD line, and a RX FIFO overrun on APBUART2 are to be detected and appropriate error handling and reporting of these conditions is required.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The memory protection features of the GR716 are to be used to protect the APBUART2 configuration.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Design Outline ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt; A circular buffer will be used for the internal buffer to allow flexibility in adding and removing characters. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; A data structure associated with APBUART2 will be used to hold this buffer and status information. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt; Processing will be structured as an interrupt handler I_HANDLER and a task T_PROCESS. An idle task T_IDLE will enable the device interrupt after scheduling begins. &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER will add characters to the buffer and start T_PROCESS when this becomes ¾ full, when a command is detected in the input stream, or when there is a parity error, break condition, or RX FIFO overrun. Status flags in the device data structure will indicate the reason for starting T_PROCESS. The number of interrupts is to be minimised while ensuring a timely response to a single character command and to anomalies.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will remove data from the buffer, reset the status flags, and handle any commands or error conditions. Once started it will loop checking the status and will exit when there is nothing for it to do. Entries may be added to the internal buffer by I_HANDLER while T_PROCESS is running.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;One single character command ‘esc’ and two other commands “#a” and “#b” are to be recognised, and all other character sequences treated as data text.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(For this example what T_PROCESS does with the data, or what it does once it recognises a command, are not developed further.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;A low priority idle task T_IDLE will also be created. Initially this will enable the device interrupt and then loop indefinitely, putting the CPU in sleep mode waiting for interrupts at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before developing the design further it is necessary to consider the settings needed for APBUART2 and the initialisation required for clock gating, GPIO pin mapping, interrupts, and memory protection.&amp;lt;/p&amp;gt;&lt;br /&gt;
=== APBUART Configuration ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each APBUART has two internal 16 byte FIFO buffers for transmit (TX) and receive (RX). These are accessed via the 32-bit data register (DATA) with only the low 8-bits of this register actually used. A read of DATA provides the oldest byte in the RX FIFO as the low byte in the word returned and removes it from the RX FIFO. Writing to DATA adds the low byte in the word to the TX FIFO from which it is removed by the transmitter. For testing purposes a loop back mode can be set so that the TX output is internally connected to the RX input and actual outputs are disabled. A FIFO debug mode can also be set that disables the transmitter and allows the FIFO debug register (FIFO) be used to read from the RX FIFO and write to the TX FIFO.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In each APBUART the baud rate used is the same for receive and transmit and is determined by the value set in its scaler register (SCALER). This value should be the number of system clock cycles that corresponds to 1/8 of the time for one serial bit, or as close as possible to this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The data format used is always 8 bits per character, with an optional even or odd parity bit, and one stop bit. The transmitter can be set to use two stop bits.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Hardware flow control can be used, with the input CTSN signal controlling transmission from the APBUART, and the output RTSN signal connected to the source of the incoming data.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example, the APBUART2 control register (CTRL) and scaler register (SCALER) are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|CTRL&lt;br /&gt;
|0x80003025&lt;br /&gt;
|&amp;lt;p&amp;gt;Even parity (PE, PS=0)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver enable (RE)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver interrupt enable (RI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;delayed interrupt enable (DI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;break interrupt enable (BI)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Receiver FIFO interrupt enable (RF)&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Other control bits all 0&amp;lt;/p&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|SCALLER&lt;br /&gt;
|0xAB&lt;br /&gt;
|(Baud rate 38400 at 50 MHz system clock)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note that while interrupts are enabled here, APBUART2 interrupts are disabled initially in the interrupt controller IRQAMP and only enabled by T_IDLE after scheduling begins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings ensure that an interrupt is generated after every character is received, but only after a gap of just over four character times without a character, so that a block of characters received in quick succession will cause only one interrupt. In case such a block succeeds in filling the RX FIFO an interrupt is also generated when the RX FIFO is half full. An interrupt is also caused by a parity error, a break on the RX line, i.e. line held low for longer than 11 bits, or a RX FIFO overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;With the above settings each incoming character corresponds to about 15,000 system clock cycles, so if a FIFO half full interrupt occurs it will take at least 120,000 system clock cycles before a further 8 bytes can arrive potentially causing a FIFO overrun and loss of an incoming byte. The interrupt latency and time to remove the first byte from the RX FIFO needs to be guaranteed to be less than this by appropriate choice of the interrupt priority.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;These control settings might be assigned in many other ways. It might for example be desirable to cause an interrupt immediately on arrival of a character so as to avoid the four-character latency above.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Before the APBUART2 control bits are set the clock gating, GPIO pin allocations, interrupt controller, and memory protection need to be configured, and these are considered next.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Clock gating ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To use a GR716 device, or to modify its registers, the clock gating for the device must be enabled. In the initialisation sequence clock gating can be used to ensure a device is off. To save power when a device is not in use clock gating may also be used at various points in an application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 the APBUART clocks are controlled by the primary clock gating unit. This unit’s unlock register UNLOCK0, its clock enable register CLKEN0 and its core reset register RESTET0 all use Bit 18 to correspond to APBUART2. To modify a bit in CLKEN0 or RESET0 the corresponding bit in UNLOCK0 must first be set, and should be reset to 0 once the desired changes have been made to protect against unintended changes.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;''(Note: The GR716 documentation uses UNLOCK1 etc. to refer to these registers, but this appears to be a misprint, as they are also referred to as ‘Unlock register 0’ etc. and UNLOCK1 etc. is also used in referring to the secondary clock gating unit, so ‘0’ is used here rather than ‘1’.)''&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Disable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Ensure no software is using the APBUART2 and that it cannot cause an interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
Enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Set UNLOCK0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set RESET0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Reset CLKEN0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Reset RESET0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set CLKEN0 bit 18 to 1&amp;lt;/li&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Reset UNLOCK0 bit 18 to 0&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== GPIO Mapping ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In the GR716 most input-output pins can be allocated to any one of a number of devices as determined by an I/O switch matrix that must be configured appropriately by the application.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;APBUART2 uses GPIO[10] and GPIO[11] for its external TXD and RXD data lines respectively. These GPIO pins can be used for 8 different purposes, and to allocate them for use by APBUART2 the appropriate value must be written to the appropriate system configuration register.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;For pins GPIO[10] and GPIO[11] the appropriate configuration register is SYS.CFG.GP1. In SYS.CFG.GP1 bits 8:11 determine the allocation of GPIO[10] and bits 12:15 of GPIO[11], and in both cases the pin is allocated to APBUART2 (TXD and RXD respectively) by setting these 4 bits to 0b0001.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Care is needed in writing to SYS.CFG.GP1 as other bit positions determine the allocation of other pins.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;N.B. GPIO mapping consistency should be checked, perhaps using OCE’s DMON or Gaisler’s grmon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;It is worth noting also that when a device is disabled its associated pins are returned to GPIO input.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Each device on the GR716 has a fixed hardware Interrupt Line that is mapped to an Interrupt ID by the Interrupt Controller (IRQAMP). This mapping can be changed by writing to a register on IRQAMP.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The Interrupt ID in conjunction with its associated 0 or 1 interrupt level determines the priority of an interrupt. The highest priority interrupt is passed to the CPU and determines the interrupt handler used. Interrupts can be masked so that a specific interrupt is ignored until the interrupt is unmasked. After reset all interrupts are masked, i.e. disabled (IRQAMP.PIMASK = 0x00000000).&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The default interrupt ID assignments for the six APBUARTs are:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
!APBUART&lt;br /&gt;
!Interrupt Line&lt;br /&gt;
!Interrupt ID&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|24&lt;br /&gt;
|24&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|25&lt;br /&gt;
|25&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|42&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|44&lt;br /&gt;
|5&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|45&lt;br /&gt;
|6&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|46&lt;br /&gt;
|7&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 Interrupt Controller IRQAMP can be used to change these assignments.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;For this example the default assignment is used for APBUART2, i.e. interrupt ID = 3&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Initially Interrupt 3 is configured:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Ensure Masked OFF&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK X&amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Set level HIGH&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ILEVEL |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Check no timestamp used&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.TSISEL != 3 for IRQAMP.ITSTMPC0,1,2,3&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;After APBUART2 has been configured, Interrupt 3 will be cleared and then enabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt CLEAR&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.ICLEAR |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task will periodically disable and enable the interrupt&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|Disable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK &amp;amp;= 0xfffffff7&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|Enable interrupt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;IRQAMP.PIMASK |= 0x8&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Memory Protection ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The GR716 contains two memory protection (MEMPROT) units that can be used to enable/disable writing to certain memory segments and to the configuration registers of various devices.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The MEMPROT units can be gated on or off by the primary clock gating unit, which must enable them in order for them to be configured or used. The MEMPROT units can also protect the clock gating units.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Protecting the APBUART2 configuration involves the MEMPROT registers APB3PROT0, APBPROT1, APBPROT2 and APBPROT3 and setting Bit 13 in all of these and Bit 29 in all except APBPROT1.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;CPU access to APBUART2 involves resetting/setting Bit 13 and Bit 29 of APB3PROT0 to enable/disable access from the CPU and intervening bridge. If only CPU access to APBUART2 is required access from other bus masters can be left disabled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Further Design Details ===&lt;br /&gt;
&lt;br /&gt;
''Device Data Structure'':&lt;br /&gt;
&lt;br /&gt;
 struct uart_info {&lt;br /&gt;
      unsigned int * BASE_ADDRESS // base address of APBUART2 registers&lt;br /&gt;
      unsigned int write_index : 8; // index of previous write done&lt;br /&gt;
      unsigned int read_index : 8; // index of previous read done&lt;br /&gt;
      unsigned int : 6; // spare&lt;br /&gt;
      unsigned int COMMAND_0 : 1; // initial part of command detected&lt;br /&gt;
      unsigned int COMMAND : 1; // command detected&lt;br /&gt;
      unsigned int CHAR_INT : 1;&lt;br /&gt;
      unsigned int FIFOHALF_INT : 1;&lt;br /&gt;
      unsigned int FIFOFULL_INT : 1;&lt;br /&gt;
      unsigned int PARITY_INT : 1;&lt;br /&gt;
      unsigned int BREAK_INT : 1;&lt;br /&gt;
      unsigned int BUF_FILLING : 1;&lt;br /&gt;
      unsigned int BUF_OVERRUN : 1;&lt;br /&gt;
      unsigned int RUNNING : 1;&lt;br /&gt;
      char buffer[256]; // array size is one more than buffer size&lt;br /&gt;
 }; // uart_info&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;Note:  The buffer array will be treated as a circular buffer. If full new entries will be dropped rather than overwriting older entries and the BUF_OVERRUN bit be set. An empty buffer is indicated by read and write indices being equal, so the maximum number of entries in the buffer (255) is one less than the array size.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Note: write_index is changed only by the interrupt handler&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;read_index is changed only by the task&amp;lt;/p&amp;gt;&lt;br /&gt;
::&amp;lt;p&amp;gt;status bits are changed only in the interrupt handler or with interrupts disabled&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The bits of the status field will typically be set by the I_HANDLER and reset by T_PROCESS.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler and Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;I_HANDLER starts T_PROCESS but does not need to do so if T_PROCESS is already active.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS loops until the buffer is empty and there are no anomalies to handle, but must then exit rather than continue looping to allow lower priority tasks become active. I_HANDLER need only start T_PROCESS again if T_PROCESS has exited its main loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;To facilitate this a status bit RUNNING is set by I_HANDLER when it starts T_PROCESS, and is cleared by T_PROCESS when it determines the buffer is empty and there is no anomaly to be handled.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS still has to exit after clearing RUNNING, it must be possible for two T_PROCESS jobs to exist simultaneously, the old one finishing up, and the new one just started. OCEOS will not schedule the new job until the old one has completed so no more than two T_PROCESS jobs can be in existence at the same time and the maximum number of jobs for T_PROCESS can be limited to two.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interrupt Handler ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An APBUART2 interrupt is caused by&amp;lt;/p&amp;gt;&lt;br /&gt;
# A character arriving and no further character having arrived after four character times&lt;br /&gt;
# The RX FIFO becoming half full (eight characters)&lt;br /&gt;
# The RX FIFO being overrun&lt;br /&gt;
# A break condition on the RX line i.e. line held low for longer than 11 bits&lt;br /&gt;
# A parity error on the input&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The interrupt handler I_HANDLER updates the status bits in the uart_info structure based on the APBUART2 status register, resets the APBUART2 status register bits, and if space is available in the buffer copies the data from the RX FIFO to the buffer.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;As it copies the data to the buffer I_HANDLER recognises the presence of a single character command by setting the COMMAND bit, the start of a multi-character command by setting the COMMAND_0 bit, and the completion of a multi-character command by setting the COMMAND bit and clearing the COMMAND_0 bit.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If buffer space is not available the RX FIFO data is discarded, BUF_OVERRUN is set, and if COMMAND_0 is set it is reset since the continuation characters of the command have now been lost.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;A task is not started if RUNNING is set as the current job will recognise the new conditions.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;If RUNNING is not set I_HANDLER will set it and start T_PROCESS if any one of the following is true:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# an APBUART2 error condition has occurred&lt;br /&gt;
# BUF_OVERRUN has been set&lt;br /&gt;
# a command has been recognised in the input stream&lt;br /&gt;
# the buffer has become ¾ full.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;This approach can result in T_PROCESS locking out lower priority tasks for an indefinite period if APBUART2 is heavily loaded with incoming data, and in general this will need to be taken into account in deciding the priority of T_PROCESS. (As the idle task is the only other task in this example this is not relevant here.)&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In addition, if the processing involved in T_PROCESS is sometimes but not always heavy, perhaps due to an occasional command, it may be worth using a lower priority task than T_PROCESS to handle this heavy processing and start this task from T_PROCESS so as to ensure the primary buffer and RX FIFO are never overrun.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;One the other hand, if a high priority command is recognised it may be desirable to have T_PROCESS start a high priority task to ensure the command is dealt with promptly, without delays due to T_PROCESS being pre-empted by a higher priority task, although this will increase the risk of overruns.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;In general, deciding on the buffer size and on the relative priorities of various interrupts and of various tasks is likely to require careful consideration, although not an issue for this simple example.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Task ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;The task T_PROCESS is started by the interrupt handler I_HANDLER and does most of the processing involved in dealing with the incoming data stream.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As mentioned above, a jobs maximum of two jobs should be specified for T_PROCESS when it is created. It may be worth noting that while these two jobs may exist at the same time, one will complete execution before the other begins, as there is no time slicing in OCEOS and jobs of the same priority are scheduled for execution in the order of their creation.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;T_PROCESS will require local storage for data and for status, local_storage and local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;As T_PROCESS can be interrupted while processing the data care is needed to ensure that local_status corresponds to the local_storage data being processed. It will be necessary to disable APBUART2 interrupts at some point, in order to guarantee this.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Also while local_storage may not need separate local storage (it might instead be implemented as pointers into the internal buffer) it seems likely that it will be necessary to have explicit local storage in T_PROCESS for local_status.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Processing: T_PROCESS is structured as a loop with the following main steps 1 to 7 below:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy characters from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt (need to ensure status and data correspond)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;While uart_info.read_index != uart_info.write_index (usually already empty)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Increment uart_info.read_index (mod 256)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy character from buffer to local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Copy uart_info status bits to local_status&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset uart_info status bits to nominal (APBUART2 status bits reset by I_HANDLER)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable UART interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status not nominal (buffer overrun, RX_FIFO overrun, parity error, break)&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process anomalous condition&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If local_status.COMMAND&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Repeat until end of local_storage&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Find next command in local_storage&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Process command&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset command search start&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Disable APBUART2 interrupt&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-latin;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;p&amp;gt;If (uart_info.read_index == uart_info_write_index) (no new data)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;AND (uart_info.status is nominal) (no new problems)&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;ol style=&amp;quot;list-style-type: lower-roman;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Reset RUNNING&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Exit LOOP (task exits)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Enable APBUART2 interrupt (loop continues from 1.)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Application ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;An application that uses OCEOS&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;sets up the functions to be used by the interrupt handlers and tasks,&lt;br /&gt;
#&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;sets up the functions to be called to handle error conditions&lt;br /&gt;
#&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;determines the memory areas for OCEOS fixed, dynamic and log data&lt;br /&gt;
#&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;&amp;lt;p&amp;gt;starts executing at main()&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;main(){ (the initialisation procedures below have been described earlier)&amp;lt;/p&amp;gt;&lt;br /&gt;
#&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Use clock gating to ensure APBUART2 is disabled&lt;br /&gt;
#&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;Set interrupt controller IRQAMP for APBUART2, interrupt disabled (masked)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;Associate I_HANDLER with APBUART2 interrupt&lt;br /&gt;
#&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;Create and initialize the device data structure (described earlier)&lt;br /&gt;
#&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Set the clock gating control to enable APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;Set the GPIO control to map APBUART2 RXD and TXD to GPIO pins&lt;br /&gt;
#&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Set APBUART2 CTRL and SCALER registers&lt;br /&gt;
#&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Set the memory protection registers to protect APBUART2&lt;br /&gt;
#&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;Create and initialise an application configuration structure&lt;br /&gt;
#&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Pass the application configuration structure to oceos_init()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;15&amp;quot;&amp;gt;Create T_PROCESS task with maximum two jobs, high priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;16&amp;quot;&amp;gt;Create T_IDLE task with maximum one job, low priority&lt;br /&gt;
#&amp;lt;li value=&amp;quot;17&amp;quot;&amp;gt;Finish OCEOS initialisation using oceos_init_finish()&lt;br /&gt;
#&amp;lt;li value=&amp;quot;18&amp;quot;&amp;gt;Pass fixed data, idle task T_IDLE and null pointer to oceos_start()&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;p&amp;gt;OCEOS now starts scheduling and runs T_IDLE initially, pre-empting it whenever T_PROCESS&amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;is started by I_HANDLER. When T_IDLE starts it enables the APBUART2 interrupt, and then &amp;lt;/p&amp;gt;&lt;br /&gt;
:&amp;lt;p&amp;gt;loops indefinitely, perhaps putting the CPU in sleep mode at the end of each loop.&amp;lt;/p&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
= Two-phase build to miminise memory used =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p&amp;gt;OCEOS can be build in two phases to reduce the memory requirement. Phase I performs the initialisation of OCEOS data areas, which are saved to an object file. Phase 2 enables the application to be built without the initialisation directives where the OCEOS simply needs to be started. This significantly reduces the memory footprint.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;The steps to perform he two-phase build are as follows:&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 1:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.memory located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3 &amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;to include a new section for fixed data. The section size must include fixed data, dynamic data and log data.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 MEMORY { &lt;br /&gt;
 bootprom : ORIGIN = 0x00000000, LENGTH = 4K &lt;br /&gt;
 extprom : ORIGIN = 0x01000000, LENGTH = 16M &lt;br /&gt;
 spi0 : ORIGIN = 0x02000000, LENGTH = 32M &lt;br /&gt;
 spi1 : ORIGIN = 0x04000000, LENGTH = 32M &lt;br /&gt;
 dram : ORIGIN = 0x30001000, LENGTH = 60K &lt;br /&gt;
 fixed : ORIGIN = 0x30000000, LENGTH = 4K &lt;br /&gt;
 iram : ORIGIN = 0x31000000, LENGTH = 128K &lt;br /&gt;
 extram : ORIGIN = 0x40000000, LENGTH = 256M &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
'''Step 2:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 INCLUDE linkcmds.memory&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_TEXT&amp;quot;, iram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_FIXED_DATA&amp;quot;, fixed);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_RODATA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_VMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_DATA_LMA&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_BSS&amp;quot;, dram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_VMA&amp;quot;, extram);&lt;br /&gt;
 REGION_ALIAS(&amp;quot;REGION_EXTDATA_LMA&amp;quot;, extram);&lt;br /&gt;
 INCLUDE linkcmds.base&lt;br /&gt;
&lt;br /&gt;
'''Step 3:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Modify linkcmds.base located at C:\opt\bcc-2.1.0-llvm\sparc-gaisler-elf\bsp\gr716\leon3&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;to include new section for fixed data :&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 .fixeddata : { &lt;br /&gt;
 __fixeddata_start = .; &lt;br /&gt;
 *(.fixeddata)&lt;br /&gt;
 __fixeddata_end = .; &lt;br /&gt;
 } &amp;gt; REGION_FIXED_DATA&lt;br /&gt;
&lt;br /&gt;
'''Step 4:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Create application and include oceos_init and oceos_finish without starting oceos.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt; This part should create mutexes, dataqs, semaphores if used.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Fixed data, dynamic data and log data should be declared in the order below.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 log_data[LOG_DATA_ARRAY_SIZE_U32S] ; &lt;br /&gt;
 U32_t __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Pointers to the task functions should be declared in arrays and kept between two stages &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;(will be used in oceos_start at second stage to replace in fixed data).&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 5:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Run application on the board.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;Use DMON command to capture fixed data area.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 save fixed_data_start fixed_data_end fixed_data.bin bin&lt;br /&gt;
&lt;br /&gt;
'''Step 6:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Use objcopy utility to convert bin file to object and symbols :&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;_binary_fixed_data_bin_start, _binary_fixed_data_bin_end &amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;and _binary_fixed_data_bin_size , which can be used in application later.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Make sure to replace the default data section to fixeddata section.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $(OBJCOPY) --output-target elf32-sparc --rename-section .data=.fixeddata --input-target binary --binary-architecture sparc fixed_data.bin fixed_data.o&lt;br /&gt;
&lt;br /&gt;
'''Step 7:''' &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Remove initialization code from application.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Declare:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 extern char __attribute__((section(&amp;quot;.fixeddata&amp;quot;))) &lt;br /&gt;
 _binary_fixed_data_bin_start[];&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;and start OCEOS as follows:&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 status = oceos_start((U32_t *)&amp;amp;_binary_fixed_data_bin_start[0], t_dan, NULL);&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;The oceos_start directive will use fresh pointers to task function from task_start_func_ptr&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;and task_end_func_ptr and update it in fixed data, initialize dynamic data and start scheduling.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Step 8:'''&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;p&amp;gt;Add fixed_data.o to the linker. Linker should put content of this object file in fixeddata section created earlier.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Now the complete initialization process can be bypassed and OCEOS can be started faster with a smaller memory footprint.&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:backup]]&lt;/div&gt;</summary>
		<author><name>Wiki</name></author>
	</entry>
</feed>